diff --git a/.eslintrc.json b/.eslintrc.json
index e0c6aec..b7597ab 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -9,11 +9,24 @@
"import/no-mutable-exports": "off",
"no-nested-ternary": "off",
"no-param-reassign": "off",
- "func-names": "off"
+ "func-names": "off",
+ "max-classes-per-file": "off",
+ "react/prefer-stateless-function": "off",
+ "react/destructuring-assignment": "off",
+ "react/state-in-constructor": "off",
+ "react/prop-types": "off"
},
"globals": {
"window": true,
"EventTarget": true,
- "WebSocket": true
+ "WebSocket": true,
+ "describe": true,
+ "afterAll": true,
+ "test": true,
+ "expect": true,
+ "afterEach": true,
+ "document": true,
+ "jest": true,
+ "Event": true
}
}
diff --git a/__mocks__/react-dom.js b/__mocks__/react-dom.js
deleted file mode 100644
index 2251e01..0000000
--- a/__mocks__/react-dom.js
+++ /dev/null
@@ -1,3 +0,0 @@
-// this is here to avoid duplicate react entries in the examples
-// (one from the example's node_modules and one from the root's node_modules)
-module.exports = require('react-dom')
diff --git a/__mocks__/react-easy-state.js b/__mocks__/react-easy-state.js
index ef63051..882d144 100644
--- a/__mocks__/react-easy-state.js
+++ b/__mocks__/react-easy-state.js
@@ -1,8 +1,9 @@
-const path = require('path')
+const path = require('path');
-const bundleName = process.env.BUNDLE
+const bundleName = process.env.BUNDLE;
const bundlePath = path.resolve(
- bundleName ? `dist/${bundleName}` : 'src/index.js'
-)
+ bundleName ? `dist/${bundleName}` : 'src/index.js',
+);
-module.exports = require(bundlePath)
+// eslint-disable-next-line import/no-dynamic-require
+module.exports = require(bundlePath);
diff --git a/__mocks__/react-native.js b/__mocks__/react-native.js
index 56f6104..1230fb3 100644
--- a/__mocks__/react-native.js
+++ b/__mocks__/react-native.js
@@ -1,3 +1,3 @@
// this is here to avoid duplicate react entries in the examples
// (one from the example's node_modules and one from the root's node_modules)
-module.exports = require('react-native')
+module.exports = require('react-native');
diff --git a/__mocks__/react-platform.js b/__mocks__/react-platform.js
deleted file mode 100644
index 5909066..0000000
--- a/__mocks__/react-platform.js
+++ /dev/null
@@ -1,3 +0,0 @@
-module.exports = process.env.NATIVE
- ? require('react-native')
- : require('react-dom')
diff --git a/__mocks__/react.js b/__mocks__/react.js
index 1ee9232..5ff273d 100644
--- a/__mocks__/react.js
+++ b/__mocks__/react.js
@@ -1,3 +1,3 @@
// this is here to avoid duplicate react entries in the examples
// (one from the example's node_modules and one from the root's node_modules)
-module.exports = require('react')
+module.exports = require('react');
diff --git a/__tests__/Clock.test.js b/__tests__/Clock.test.js
deleted file mode 100644
index febce7d..0000000
--- a/__tests__/Clock.test.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import React, { StrictMode } from 'react'
-import { render, cleanup, act } from '@testing-library/react/pure'
-import sinon from 'sinon'
-import App from '../examples/clock/src/App'
-
-describe('Clock App', () => {
- const clock = sinon.useFakeTimers()
- const { container, unmount } = render(
-
-
-
- )
-
- const clearIntervalSpy = sinon.spy(global, 'clearInterval')
-
- afterAll(() => {
- cleanup()
- clock.restore()
- clearIntervalSpy.restore()
- })
-
- test('should update to display the current time every second', () => {
- expect(container).toHaveTextContent('12:00:00 AM')
-
- act(() => {
- clock.tick(2000)
- })
- expect(container).toHaveTextContent('12:00:02 AM')
-
- act(() => {
- clock.tick(8500)
- })
- expect(container).toHaveTextContent('12:00:10 AM')
- })
-
- test('should clean up the interval timer when the component is unmounted', () => {
- unmount()
- expect(clearIntervalSpy.callCount).toBe(1)
- })
-})
diff --git a/__tests__/Clock.test.jsx b/__tests__/Clock.test.jsx
new file mode 100644
index 0000000..fbd68b3
--- /dev/null
+++ b/__tests__/Clock.test.jsx
@@ -0,0 +1,40 @@
+import React, { StrictMode } from 'react';
+import { render, cleanup, act } from '@testing-library/react/pure';
+import sinon from 'sinon';
+import App from '../examples/clock/src/App';
+
+describe('Clock App', () => {
+ const clock = sinon.useFakeTimers();
+ const { container, unmount } = render(
+
+
+ ,
+ );
+
+ const clearIntervalSpy = sinon.spy(global, 'clearInterval');
+
+ afterAll(() => {
+ cleanup();
+ clock.restore();
+ clearIntervalSpy.restore();
+ });
+
+ test('should update to display the current time every second', () => {
+ expect(container).toHaveTextContent('12:00:00 AM');
+
+ act(() => {
+ clock.tick(2000);
+ });
+ expect(container).toHaveTextContent('12:00:02 AM');
+
+ act(() => {
+ clock.tick(8500);
+ });
+ expect(container).toHaveTextContent('12:00:10 AM');
+ });
+
+ test('should clean up the interval timer when the component is unmounted', () => {
+ unmount();
+ expect(clearIntervalSpy.callCount).toBe(1);
+ });
+});
diff --git a/__tests__/Clock.test.native.js b/__tests__/Clock.test.native.js
deleted file mode 100644
index c57ef6d..0000000
--- a/__tests__/Clock.test.native.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import React, { StrictMode } from 'react'
-import { render, flushMicrotasksQueue } from 'react-native-testing-library'
-import sinon from 'sinon'
-import App from '../examples/native-clock/App'
-
-describe('Clock App', () => {
- const clock = sinon.useFakeTimers()
- const { getByText, unmount } = render(
-
-
-
- )
- // flush the inital didMount effect
- flushMicrotasksQueue()
-
- const clearIntervalSpy = sinon.spy(global, 'clearInterval')
-
- afterAll(() => {
- clock.restore()
- clearIntervalSpy.restore()
- })
-
- test('should update to display the current time every second', () => {
- expect(getByText('12:00:00 AM')).toBeDefined()
-
- clock.tick(2000)
- expect(getByText('12:00:02 AM')).toBeDefined()
-
- clock.tick(8500)
- expect(getByText('12:00:10 AM')).toBeDefined()
- })
-
- test('should clean up the interval timer when the component is unmounted', () => {
- unmount()
- expect(clearIntervalSpy.callCount).toBe(1)
- })
-})
diff --git a/__tests__/Clock.test.native.jsx b/__tests__/Clock.test.native.jsx
new file mode 100644
index 0000000..8436f97
--- /dev/null
+++ b/__tests__/Clock.test.native.jsx
@@ -0,0 +1,40 @@
+import React, { StrictMode } from 'react';
+import {
+ render,
+ flushMicrotasksQueue,
+} from 'react-native-testing-library';
+import sinon from 'sinon';
+import App from '../examples/native-clock/App';
+
+describe('Clock App', () => {
+ const clock = sinon.useFakeTimers();
+ const { getByText, unmount } = render(
+
+
+ ,
+ );
+ // flush the inital didMount effect
+ flushMicrotasksQueue();
+
+ const clearIntervalSpy = sinon.spy(global, 'clearInterval');
+
+ afterAll(() => {
+ clock.restore();
+ clearIntervalSpy.restore();
+ });
+
+ test('should update to display the current time every second', () => {
+ expect(getByText('12:00:00 AM')).toBeDefined();
+
+ clock.tick(2000);
+ expect(getByText('12:00:02 AM')).toBeDefined();
+
+ clock.tick(8500);
+ expect(getByText('12:00:10 AM')).toBeDefined();
+ });
+
+ test('should clean up the interval timer when the component is unmounted', () => {
+ unmount();
+ expect(clearIntervalSpy.callCount).toBe(1);
+ });
+});
diff --git a/__tests__/Contacts.test.js b/__tests__/Contacts.test.js
deleted file mode 100644
index b1270d3..0000000
--- a/__tests__/Contacts.test.js
+++ /dev/null
@@ -1,96 +0,0 @@
-import React, { StrictMode } from 'react'
-import { render, cleanup, fireEvent } from '@testing-library/react/pure'
-import App from '../examples/contacts/src/App'
-
-describe('Contacts App', () => {
- const { container } = render(
-
-
-
- )
- afterAll(cleanup)
-
- test('should add new contacts', () => {
- expect(container).toMatchSnapshot('01. Initial state')
-
- const nameField = container.querySelector('input[name="name"]')
- const emailField = container.querySelector('input[name="email"]')
- const createButton = container.querySelector('button')
-
- fireEvent.change(nameField, {
- target: { name: 'name', value: 'Test Contact' }
- })
- expect(container).toMatchSnapshot('02. Create Test Contact name')
-
- fireEvent.change(emailField, {
- target: { name: 'email', value: 'test.contact@gmail.com' }
- })
- expect(container).toMatchSnapshot('03. Create Test Contact email')
-
- fireEvent.click(createButton)
- expect(container).toMatchSnapshot('04. Add Test Contact')
-
- fireEvent.change(nameField, {
- target: { name: 'name', value: '' }
- })
- fireEvent.change(emailField, {
- target: { name: 'email', value: '' }
- })
- fireEvent.click(createButton)
- expect(container).toMatchSnapshot('05. Add Placeholder Contact')
- })
-
- test('should edit contact', () => {
- let display, editor, editButton
-
- display = container.querySelector('.contact-display')
- editButton = display.querySelector('.zmdi-edit')
-
- fireEvent.click(editButton)
- expect(container).toMatchSnapshot('06. Switch Test Contact to Edit Mode')
-
- editor = container.querySelector('.contact-editor')
- const nameField = editor.querySelector('input[name="name"]')
- const cancelButton = editor.querySelector('.zmdi-close')
-
- fireEvent.change(nameField, {
- target: { name: 'name', value: 'Edited Test Contact' }
- })
- expect(container).toMatchSnapshot('07. Edit Test Contact name')
-
- fireEvent.click(cancelButton)
- expect(container).toMatchSnapshot('08. Cancel Test Contact edit')
-
- display = container.querySelector('.contact-display')
- editButton = display.querySelector('.zmdi-edit')
-
- fireEvent.click(editButton)
- expect(container).toMatchSnapshot('09. Switch Test Contact to edit Mode')
-
- editor = container.querySelector('.contact-editor')
- const emailField = editor.querySelector('input[name="email"]')
- const saveButton = editor.querySelector('.zmdi-save')
-
- fireEvent.change(emailField, {
- target: { name: 'email', value: 'test.contact.edited@gmail.com' }
- })
- expect(container).toMatchSnapshot('10. Edit Test Contact email')
-
- fireEvent.click(saveButton)
- expect(container).toMatchSnapshot('11. Save Test Contact edit')
- })
-
- test('should delete contact', () => {
- let deleteButton = container.querySelectorAll(
- '.contact-display .zmdi-delete'
- )[1]
-
- fireEvent.click(deleteButton)
- expect(container).toMatchSnapshot('12. Delete Placeholder Contact')
-
- deleteButton = container.querySelector('.contact-display .zmdi-delete')
-
- fireEvent.click(deleteButton)
- expect(container).toMatchSnapshot('13. Delete Test Contact')
- })
-})
diff --git a/__tests__/Contacts.test.jsx b/__tests__/Contacts.test.jsx
new file mode 100644
index 0000000..babd7bf
--- /dev/null
+++ b/__tests__/Contacts.test.jsx
@@ -0,0 +1,115 @@
+import React, { StrictMode } from 'react';
+import {
+ render,
+ cleanup,
+ fireEvent,
+} from '@testing-library/react/pure';
+import App from '../examples/contacts/src/App';
+
+describe('Contacts App', () => {
+ const { container } = render(
+
+
+ ,
+ );
+ afterAll(cleanup);
+
+ test('should add new contacts', () => {
+ expect(container).toMatchSnapshot('01. Initial state');
+
+ const nameField = container.querySelector('input[name="name"]');
+ const emailField = container.querySelector('input[name="email"]');
+ const createButton = container.querySelector('button');
+
+ fireEvent.change(nameField, {
+ target: { name: 'name', value: 'Test Contact' },
+ });
+ expect(container).toMatchSnapshot('02. Create Test Contact name');
+
+ fireEvent.change(emailField, {
+ target: { name: 'email', value: 'test.contact@gmail.com' },
+ });
+ expect(container).toMatchSnapshot(
+ '03. Create Test Contact email',
+ );
+
+ fireEvent.click(createButton);
+ expect(container).toMatchSnapshot('04. Add Test Contact');
+
+ fireEvent.change(nameField, {
+ target: { name: 'name', value: '' },
+ });
+ fireEvent.change(emailField, {
+ target: { name: 'email', value: '' },
+ });
+ fireEvent.click(createButton);
+ expect(container).toMatchSnapshot('05. Add Placeholder Contact');
+ });
+
+ test('should edit contact', () => {
+ let display;
+ let editor;
+ let editButton;
+
+ display = container.querySelector('.contact-display');
+ editButton = display.querySelector('.zmdi-edit');
+
+ fireEvent.click(editButton);
+ expect(container).toMatchSnapshot(
+ '06. Switch Test Contact to Edit Mode',
+ );
+
+ editor = container.querySelector('.contact-editor');
+ const nameField = editor.querySelector('input[name="name"]');
+ const cancelButton = editor.querySelector('.zmdi-close');
+
+ fireEvent.change(nameField, {
+ target: { name: 'name', value: 'Edited Test Contact' },
+ });
+ expect(container).toMatchSnapshot('07. Edit Test Contact name');
+
+ fireEvent.click(cancelButton);
+ expect(container).toMatchSnapshot('08. Cancel Test Contact edit');
+
+ display = container.querySelector('.contact-display');
+ editButton = display.querySelector('.zmdi-edit');
+
+ fireEvent.click(editButton);
+ expect(container).toMatchSnapshot(
+ '09. Switch Test Contact to edit Mode',
+ );
+
+ editor = container.querySelector('.contact-editor');
+ const emailField = editor.querySelector('input[name="email"]');
+ const saveButton = editor.querySelector('.zmdi-save');
+
+ fireEvent.change(emailField, {
+ target: {
+ name: 'email',
+ value: 'test.contact.edited@gmail.com',
+ },
+ });
+ expect(container).toMatchSnapshot('10. Edit Test Contact email');
+
+ fireEvent.click(saveButton);
+ expect(container).toMatchSnapshot('11. Save Test Contact edit');
+ });
+
+ test('should delete contact', () => {
+ let deleteButton = container.querySelectorAll(
+ '.contact-display .zmdi-delete',
+ )[1];
+
+ fireEvent.click(deleteButton);
+ expect(container).toMatchSnapshot(
+ '12. Delete Placeholder Contact',
+ );
+
+ deleteButton = container.querySelector(
+ '.contact-display .zmdi-delete',
+ );
+
+ fireEvent.click(deleteButton);
+ expect(container).toMatchSnapshot('13. Delete Test Contact');
+ });
+});
diff --git a/__tests__/TodoMVC.test.js b/__tests__/TodoMVC.test.js
deleted file mode 100644
index f0db1a6..0000000
--- a/__tests__/TodoMVC.test.js
+++ /dev/null
@@ -1,94 +0,0 @@
-import React, { StrictMode } from 'react'
-import { render, cleanup, fireEvent } from '@testing-library/react/pure'
-import App from '../examples/todo-mvc/src/App'
-
-describe('TodoMVC App', () => {
- const { container } = render(
-
-
-
- )
- afterAll(cleanup)
-
- test('should add todos', () => {
- expect(container).toMatchSnapshot('01. Initial state')
-
- const input = container.querySelector('.new-todo')
-
- fireEvent.keyUp(input, {
- keyCode: 13,
- target: { value: 'Test Todo' }
- })
- expect(container).toMatchSnapshot('02. Add Test Todo')
-
- fireEvent.keyUp(input, {
- keyCode: 13,
- target: { value: 'Other Todo' }
- })
- expect(container).toMatchSnapshot('03. Add Other Todo')
-
- fireEvent.keyUp(input, {
- keyCode: 27,
- target: { value: 'Final Tod' }
- })
- fireEvent.keyUp(input, {
- keyCode: 13,
- target: { value: 'Final Todo' }
- })
- expect(container).toMatchSnapshot('04. Add Final Todo')
- })
-
- test('should toggle todo status', () => {
- const toggles = container.querySelectorAll('.todo-list .toggle')
-
- fireEvent.click(toggles[0])
- expect(container).toMatchSnapshot('05. Toggle Test Todo to completed')
-
- fireEvent.click(toggles[1])
- expect(container).toMatchSnapshot('06. Toggle Other Todo to completed')
-
- fireEvent.click(toggles[0])
- expect(container).toMatchSnapshot('07. Toggle Test Todo to active')
- })
-
- test('should filter todos', () => {
- const completedFilter = container.querySelector(
- 'button[value="completed"]'
- )
- const activeFilter = container.querySelector('button[value="active"]')
- const allFilter = container.querySelector('button[value="all"]')
-
- fireEvent.click(completedFilter)
- expect(container).toMatchSnapshot('08. Filter completed')
-
- fireEvent.click(activeFilter)
- expect(container).toMatchSnapshot('09. Filter active')
-
- fireEvent.click(allFilter)
- expect(container).toMatchSnapshot('10. Filter all')
- })
-
- test('should clear completed', () => {
- const clearCompleted = container.querySelector('.clear-completed')
-
- fireEvent.click(clearCompleted)
- expect(container).toMatchSnapshot('11. Clear completed')
- })
-
- test('should toggle all todo state at once', () => {
- const toggleAll = container.querySelector('.toggle-all')
-
- fireEvent.click(toggleAll)
- expect(container).toMatchSnapshot('12. Toggle all to completed')
-
- fireEvent.click(toggleAll)
- expect(container).toMatchSnapshot('13. Toggle all to active')
- })
-
- test('should delete todo', () => {
- const deleter = container.querySelector('.todo-list .destroy')
-
- fireEvent.click(deleter)
- expect(container).toMatchSnapshot('14. Delete Test Todo')
- })
-})
diff --git a/__tests__/TodoMVC.test.jsx b/__tests__/TodoMVC.test.jsx
new file mode 100644
index 0000000..7c1b836
--- /dev/null
+++ b/__tests__/TodoMVC.test.jsx
@@ -0,0 +1,108 @@
+import React, { StrictMode } from 'react';
+import {
+ render,
+ cleanup,
+ fireEvent,
+} from '@testing-library/react/pure';
+import App from '../examples/todo-mvc/src/App';
+
+describe('TodoMVC App', () => {
+ const { container } = render(
+
+
+ ,
+ );
+ afterAll(cleanup);
+
+ test('should add todos', () => {
+ expect(container).toMatchSnapshot('01. Initial state');
+
+ const input = container.querySelector('.new-todo');
+
+ fireEvent.keyUp(input, {
+ keyCode: 13,
+ target: { value: 'Test Todo' },
+ });
+ expect(container).toMatchSnapshot('02. Add Test Todo');
+
+ fireEvent.keyUp(input, {
+ keyCode: 13,
+ target: { value: 'Other Todo' },
+ });
+ expect(container).toMatchSnapshot('03. Add Other Todo');
+
+ fireEvent.keyUp(input, {
+ keyCode: 27,
+ target: { value: 'Final Tod' },
+ });
+ fireEvent.keyUp(input, {
+ keyCode: 13,
+ target: { value: 'Final Todo' },
+ });
+ expect(container).toMatchSnapshot('04. Add Final Todo');
+ });
+
+ test('should toggle todo status', () => {
+ const toggles = container.querySelectorAll('.todo-list .toggle');
+
+ fireEvent.click(toggles[0]);
+ expect(container).toMatchSnapshot(
+ '05. Toggle Test Todo to completed',
+ );
+
+ fireEvent.click(toggles[1]);
+ expect(container).toMatchSnapshot(
+ '06. Toggle Other Todo to completed',
+ );
+
+ fireEvent.click(toggles[0]);
+ expect(container).toMatchSnapshot(
+ '07. Toggle Test Todo to active',
+ );
+ });
+
+ test('should filter todos', () => {
+ const completedFilter = container.querySelector(
+ 'button[value="completed"]',
+ );
+ const activeFilter = container.querySelector(
+ 'button[value="active"]',
+ );
+ const allFilter = container.querySelector('button[value="all"]');
+
+ fireEvent.click(completedFilter);
+ expect(container).toMatchSnapshot('08. Filter completed');
+
+ fireEvent.click(activeFilter);
+ expect(container).toMatchSnapshot('09. Filter active');
+
+ fireEvent.click(allFilter);
+ expect(container).toMatchSnapshot('10. Filter all');
+ });
+
+ test('should clear completed', () => {
+ const clearCompleted = container.querySelector(
+ '.clear-completed',
+ );
+
+ fireEvent.click(clearCompleted);
+ expect(container).toMatchSnapshot('11. Clear completed');
+ });
+
+ test('should toggle all todo state at once', () => {
+ const toggleAll = container.querySelector('.toggle-all');
+
+ fireEvent.click(toggleAll);
+ expect(container).toMatchSnapshot('12. Toggle all to completed');
+
+ fireEvent.click(toggleAll);
+ expect(container).toMatchSnapshot('13. Toggle all to active');
+ });
+
+ test('should delete todo', () => {
+ const deleter = container.querySelector('.todo-list .destroy');
+
+ fireEvent.click(deleter);
+ expect(container).toMatchSnapshot('14. Delete Test Todo');
+ });
+});
diff --git a/__tests__/__snapshots__/Contacts.test.js.snap b/__tests__/__snapshots__/Contacts.test.jsx.snap
similarity index 100%
rename from __tests__/__snapshots__/Contacts.test.js.snap
rename to __tests__/__snapshots__/Contacts.test.jsx.snap
diff --git a/__tests__/__snapshots__/TodoMVC.test.js.snap b/__tests__/__snapshots__/TodoMVC.test.jsx.snap
similarity index 100%
rename from __tests__/__snapshots__/TodoMVC.test.js.snap
rename to __tests__/__snapshots__/TodoMVC.test.jsx.snap
diff --git a/__tests__/batching.test.js b/__tests__/batching.test.jsx
similarity index 96%
rename from __tests__/batching.test.js
rename to __tests__/batching.test.jsx
index b77ce86..9ccbc98 100644
--- a/__tests__/batching.test.js
+++ b/__tests__/batching.test.jsx
@@ -1,5 +1,6 @@
import React, { Component } from 'react';
import { render, cleanup, act } from '@testing-library/react/pure';
+// eslint-disable-next-line import/no-unresolved
import { view, store, batch } from 'react-easy-state';
describe('batching', () => {
@@ -9,7 +10,7 @@ describe('batching', () => {
let renderCount = 0;
const person = store({ name: 'Bob' });
const MyComp = view(() => {
- renderCount++;
+ renderCount += 1;
return
{person.name}
;
});
@@ -32,7 +33,7 @@ describe('batching', () => {
const MyComp = view(
class extends Component {
render() {
- renderCount++;
+ renderCount += 1;
return {person.name}
;
}
},
@@ -53,7 +54,7 @@ describe('batching', () => {
let renderCount = 0;
const person = store({ name: 'Bob' });
const MyComp = view(() => {
- renderCount++;
+ renderCount += 1;
return {person.name}
;
});
@@ -74,7 +75,7 @@ describe('batching', () => {
let renderCount = 0;
const person = store({ name: 'Bob' });
const MyComp = view(() => {
- renderCount++;
+ renderCount += 1;
return {person.name}
;
});
@@ -100,7 +101,7 @@ describe('batching', () => {
let renderCount = 0;
const person = store({ name: 'Bob' });
const MyComp = view(() => {
- renderCount++;
+ renderCount += 1;
return {person.name}
;
});
@@ -128,7 +129,7 @@ describe('batching', () => {
let renderCount = 0;
const person = store({ name: 'Bob' });
const MyComp = view(() => {
- renderCount++;
+ renderCount += 1;
return {person.name}
;
});
@@ -152,7 +153,7 @@ describe('batching', () => {
let renderCount = 0;
const person = store({ name: 'Bob' });
const MyComp = view(() => {
- renderCount++;
+ renderCount += 1;
return {person.name}
;
});
@@ -179,7 +180,7 @@ describe('batching', () => {
let renderCount = 0;
const person = store({ name: 'Bob' });
const MyComp = view(() => {
- renderCount++;
+ renderCount += 1;
return {person.name}
;
});
@@ -205,7 +206,7 @@ describe('batching', () => {
let renderCount = 0;
const person = store({ name: 'Bob' });
const MyComp = view(() => {
- renderCount++;
+ renderCount += 1;
return {person.name}
;
});
@@ -235,7 +236,7 @@ describe('batching', () => {
let renderCount = 0;
const person = store({ name: 'Bob' });
const MyComp = view(() => {
- renderCount++;
+ renderCount += 1;
return {person.name}
;
});
@@ -281,7 +282,9 @@ describe('batching', () => {
test('should not break event listeners', () => {
let callCount = 0;
- const fn = () => callCount++;
+ const fn = () => {
+ callCount += 1;
+ };
document.body.addEventListener('click', fn);
expect(callCount).toBe(0);
diff --git a/__tests__/edgeCases.test.js b/__tests__/edgeCases.test.js
deleted file mode 100644
index ade77eb..0000000
--- a/__tests__/edgeCases.test.js
+++ /dev/null
@@ -1,236 +0,0 @@
-import React, { Component, useState } from 'react'
-import { render, cleanup, fireEvent, act } from '@testing-library/react/pure'
-import { view, store, batch } from 'react-easy-state'
-
-describe('edge cases', () => {
- afterEach(cleanup)
-
- test('view() should respect shouldComponentUpdate', () => {
- const person = store({ name: 'Bob' })
- const MyComp = view(
- class extends Component {
- shouldComponentUpdate () {
- return false
- }
-
- render () {
- return {person.name}
- }
- }
- )
-
- const { container } = render()
- expect(container).toHaveTextContent('Bob')
- person.name = 'Ann'
- expect(container).toHaveTextContent('Bob')
- })
-
- test('view() should respect componentWillUnmount', () => {
- let didUnMount = false
-
- const MyComp = view(
- class extends Component {
- componentWillUnmount () {
- didUnMount = true
- }
-
- render () {
- return Hello
- }
- }
- )
-
- const { unmount } = render()
- expect(didUnMount).toBe(false)
- unmount()
- expect(didUnMount).toBe(true)
- })
-
- test('should not change vanilla setState behavior', () => {
- const MyComp = view(
- class extends Component {
- state = { counter: 0 };
- handleIncrement = () =>
- this.setState({ counter: this.state.counter + 1 });
-
- render () {
- return {this.state.counter}
- }
- }
- )
-
- const { container } = render()
- expect(container).toHaveTextContent('0')
- fireEvent.click(container.querySelector('div'))
- expect(container).toHaveTextContent('1')
- })
-
- test("should not render when state or props don't change", () => {
- const MyComp = view(
- class extends Component {
- state = { counter: 0 };
- handleIncrement = () =>
- this.setState({ counter: this.state.counter + 1 });
-
- render () {
- return (
-
-
-
-
- )
- }
- }
- )
-
- const RawChild = jest.fn().mockReturnValue(Test
)
- const Child = view(RawChild)
-
- const { container } = render()
- expect(RawChild.mock.calls.length).toBe(1)
- fireEvent.click(container.querySelector('button'))
- expect(RawChild.mock.calls.length).toBe(1)
- })
-
- test('view() should respect custom deriveStoresFromProps', () => {
- const MyComp = view(
- class extends Component {
- store1 = store({ num: 0 });
- store2 = store({ num: 1 });
-
- static deriveStoresFromProps (props, store1, store2) {
- store1.num = props.num1 || store1.num
- store2.num = props.num2 || store2.num
- }
-
- handleOnClick = () => this.store1.num++;
-
- render () {
- return (
-
- {this.store1.num}
- {this.store2.num}
-
- )
- }
- }
- )
-
- const { container } = render()
- expect(container).toHaveTextContent('11')
- fireEvent.click(container.querySelector('div'))
- expect(container).toHaveTextContent('11')
- })
-
- test('view() should respect getDerivedStateFromProps', () => {
- const MyComp = view(
- class extends Component {
- state = { num: 2 };
- static getDerivedStateFromProps (props, state) {
- return {
- num: props.num || state.num
- }
- }
-
- render () {
- return {this.state.num}
- }
- }
- )
-
- const { container } = render()
- expect(container).toHaveTextContent('2')
- })
-
- test('view() should work with other hooks', () => {
- const MyComp = view(() => {
- const [num, setNum] = useState(0)
- return
- })
-
- const { container } = render()
- expect(container).toHaveTextContent('0')
- fireEvent.click(container.querySelector('button'))
- expect(container).toHaveTextContent('1')
- })
-
- describe('reactive renders should run in parent - child order with no duplicate child runs from props', () => {
- test('should work with function components', () => {
- const appStore = store({ num: 1, nested: { num: 12 } })
-
- function change () {
- appStore.num = 0
- appStore.nested = undefined
- }
-
- let parentCalls = 0
- let childCalls = 0
-
- const Child = view(function Child () {
- childCalls++
- return (
-
- {appStore.nested.num}, {appStore.num}
-
- )
- })
-
- const Parent = view(function Parent () {
- parentCalls++
- return appStore.nested ? : null
- })
-
- const { container } = render()
- expect(container).toHaveTextContent('12, 1')
- expect(parentCalls).toBe(1)
- expect(childCalls).toBe(1)
- act(() => batch(change))
- expect(container).toHaveTextContent('')
- expect(parentCalls).toBe(2)
- expect(childCalls).toBe(1)
- })
-
- test('should work with class components', () => {
- const appStore = store({ num: 1, nested: { num: 12 } })
-
- function change () {
- appStore.num = 0
- appStore.nested = undefined
- }
-
- let parentCalls = 0
- let childCalls = 0
-
- const Child = view(
- class Child extends Component {
- render () {
- childCalls++
- return (
-
- {appStore.nested.num}, {appStore.num}
-
- )
- }
- }
- )
-
- const Parent = view(
- class Parent extends Component {
- render () {
- parentCalls++
- return appStore.nested ? : null
- }
- }
- )
-
- const { container } = render()
- expect(container).toHaveTextContent('12, 1')
- expect(parentCalls).toBe(1)
- expect(childCalls).toBe(1)
- act(() => batch(change))
- expect(container).toHaveTextContent('')
- expect(parentCalls).toBe(2)
- expect(childCalls).toBe(1)
- })
- })
-})
diff --git a/__tests__/edgeCases.test.jsx b/__tests__/edgeCases.test.jsx
new file mode 100644
index 0000000..cf58c75
--- /dev/null
+++ b/__tests__/edgeCases.test.jsx
@@ -0,0 +1,259 @@
+import React, { Component, useState } from 'react';
+import {
+ render,
+ cleanup,
+ fireEvent,
+ act,
+} from '@testing-library/react/pure';
+// eslint-disable-next-line import/no-unresolved
+import { view, store, batch } from 'react-easy-state';
+
+describe('edge cases', () => {
+ afterEach(cleanup);
+
+ test('view() should respect shouldComponentUpdate', () => {
+ const person = store({ name: 'Bob' });
+ const MyComp = view(
+ class extends Component {
+ shouldComponentUpdate() {
+ return false;
+ }
+
+ render() {
+ return {person.name}
;
+ }
+ },
+ );
+
+ const { container } = render();
+ expect(container).toHaveTextContent('Bob');
+ person.name = 'Ann';
+ expect(container).toHaveTextContent('Bob');
+ });
+
+ test('view() should respect componentWillUnmount', () => {
+ let didUnMount = false;
+
+ const MyComp = view(
+ class extends Component {
+ componentWillUnmount() {
+ didUnMount = true;
+ }
+
+ render() {
+ return Hello
;
+ }
+ },
+ );
+
+ const { unmount } = render();
+ expect(didUnMount).toBe(false);
+ unmount();
+ expect(didUnMount).toBe(true);
+ });
+
+ test('should not change vanilla setState behavior', () => {
+ const MyComp = view(
+ class extends Component {
+ state = { counter: 0 };
+
+ handleIncrement = () => {
+ this.setState(prevState => ({
+ counter: prevState.counter + 1,
+ }));
+ };
+
+ render() {
+ return (
+
+ );
+ }
+ },
+ );
+
+ const { container } = render();
+ expect(container).toHaveTextContent('0');
+ fireEvent.click(container.querySelector('button'));
+ expect(container).toHaveTextContent('1');
+ });
+
+ test("should not render when state or props don't change", () => {
+ const MyComp = view(
+ class extends Component {
+ state = { counter: 0 };
+
+ handleIncrement = () => {
+ this.setState(prevState => ({
+ counter: prevState.counter + 1,
+ }));
+ };
+
+ render() {
+ return (
+
+
+
+
+ );
+ }
+ },
+ );
+
+ const RawChild = jest.fn().mockReturnValue(Test
);
+ const Child = view(RawChild);
+
+ const { container } = render();
+ expect(RawChild.mock.calls.length).toBe(1);
+ fireEvent.click(container.querySelector('button'));
+ expect(RawChild.mock.calls.length).toBe(1);
+ });
+
+ test('view() should respect custom deriveStoresFromProps', () => {
+ const MyComp = view(
+ class extends Component {
+ // eslint-disable-next-line react/sort-comp
+ store1 = store({ num: 0 });
+
+ store2 = store({ num: 1 });
+
+ static deriveStoresFromProps(props, store1, store2) {
+ store1.num = props.num1 || store1.num;
+ store2.num = props.num2 || store2.num;
+ }
+
+ handleOnClick = () => {
+ this.store1.num += 1;
+ };
+
+ render() {
+ return (
+
+ );
+ }
+ },
+ );
+
+ const { container } = render();
+ expect(container).toHaveTextContent('11');
+ fireEvent.click(container.querySelector('button'));
+ expect(container).toHaveTextContent('11');
+ });
+
+ test('view() should respect getDerivedStateFromProps', () => {
+ const MyComp = view(
+ class extends Component {
+ state = { num: 2 };
+
+ static getDerivedStateFromProps(props, state) {
+ return {
+ num: props.num || state.num,
+ };
+ }
+
+ render() {
+ return {this.state.num}
;
+ }
+ },
+ );
+
+ const { container } = render();
+ expect(container).toHaveTextContent('2');
+ });
+
+ test('view() should work with other hooks', () => {
+ const MyComp = view(() => {
+ const [num, setNum] = useState(0);
+ return (
+
+ );
+ });
+
+ const { container } = render();
+ expect(container).toHaveTextContent('0');
+ fireEvent.click(container.querySelector('button'));
+ expect(container).toHaveTextContent('1');
+ });
+
+ describe('reactive renders should run in parent - child order with no duplicate child runs from props', () => {
+ test('should work with function components', () => {
+ const appStore = store({ num: 1, nested: { num: 12 } });
+
+ function change() {
+ appStore.num = 0;
+ appStore.nested = undefined;
+ }
+
+ let parentCalls = 0;
+ let childCalls = 0;
+
+ const Child = view(function Child() {
+ childCalls += 1;
+ return {`${appStore.nested.num}, ${appStore.num}`}
;
+ });
+
+ const Parent = view(function Parent() {
+ parentCalls += 1;
+ return appStore.nested ? : null;
+ });
+
+ const { container } = render();
+ expect(container).toHaveTextContent('12, 1');
+ expect(parentCalls).toBe(1);
+ expect(childCalls).toBe(1);
+ act(() => batch(change));
+ expect(container).toHaveTextContent('');
+ expect(parentCalls).toBe(2);
+ expect(childCalls).toBe(1);
+ });
+
+ test('should work with class components', () => {
+ const appStore = store({ num: 1, nested: { num: 12 } });
+
+ function change() {
+ appStore.num = 0;
+ appStore.nested = undefined;
+ }
+
+ let parentCalls = 0;
+ let childCalls = 0;
+
+ const Child = view(
+ class Child extends Component {
+ render() {
+ childCalls += 1;
+ return (
+ {`${appStore.nested.num}, ${appStore.num}`}
+ );
+ }
+ },
+ );
+
+ const Parent = view(
+ class Parent extends Component {
+ render() {
+ parentCalls += 1;
+ return appStore.nested ? : null;
+ }
+ },
+ );
+
+ const { container } = render();
+ expect(container).toHaveTextContent('12, 1');
+ expect(parentCalls).toBe(1);
+ expect(childCalls).toBe(1);
+ act(() => batch(change));
+ expect(container).toHaveTextContent('');
+ expect(parentCalls).toBe(2);
+ expect(childCalls).toBe(1);
+ });
+ });
+});
diff --git a/__tests__/router.test.js b/__tests__/router.test.js
deleted file mode 100644
index 6d39948..0000000
--- a/__tests__/router.test.js
+++ /dev/null
@@ -1,108 +0,0 @@
-import React, { Component } from 'react'
-import { render, cleanup, fireEvent, act } from '@testing-library/react/pure'
-import { view, store } from 'react-easy-state'
-import {
- BrowserRouter as Router,
- Route,
- Link,
- withRouter
-} from 'react-router-dom'
-
-describe('withRouter interaction', () => {
- afterEach(() => {
- cleanup()
- window.history.replaceState({}, '', '/')
- })
-
- describe('function components', () => {
- test('should be reactive with withRouter(view(Comp))', () => {
- const counter = store({ num: 0 })
- const MyComp = withRouter(view(() => {counter.num}
))
-
- const { container } = render(
-
-
-
- )
- expect(container).toHaveTextContent('0')
- act(() => {
- counter.num++
- })
- expect(container).toHaveTextContent('1')
- })
-
- test('should properly route with withRouter(view(Comp))', () => {
- const MyComp = withRouter(
- view(() => (
-
-
To Settings
-
Settings
} />
-
- ))
- )
-
- const { container, getByText } = render(
-
-
-
- )
-
- expect(container.querySelector('p')).toBe(null)
- fireEvent.click(getByText('To Settings'))
- expect(container.querySelector('p')).toHaveTextContent('Settings')
- })
- })
-
- describe('class components', () => {
- test('should be reactive with withRouter(view(Comp))', () => {
- const counter = store({ num: 0 })
- const MyComp = withRouter(
- view(
- class MyComp extends Component {
- render () {
- return {counter.num}
- }
- }
- )
- )
-
- const { container } = render(
-
-
-
- )
- expect(container).toHaveTextContent('0')
- act(() => {
- counter.num++
- })
- expect(container).toHaveTextContent('1')
- })
-
- test('should properly route with withRouter(view(Comp))', () => {
- const MyComp = withRouter(
- view(
- class MyComp extends Component {
- render () {
- return (
-
-
To Settings
-
Settings
} />
-
- )
- }
- }
- )
- )
-
- const { container, getByText } = render(
-
-
-
- )
-
- expect(container.querySelector('p')).toBe(null)
- fireEvent.click(getByText('To Settings'))
- expect(container.querySelector('p')).toHaveTextContent('Settings')
- })
- })
-})
diff --git a/__tests__/router.test.jsx b/__tests__/router.test.jsx
new file mode 100644
index 0000000..d00edf5
--- /dev/null
+++ b/__tests__/router.test.jsx
@@ -0,0 +1,121 @@
+import React, { Component } from 'react';
+import {
+ render,
+ cleanup,
+ fireEvent,
+ act,
+} from '@testing-library/react/pure';
+// eslint-disable-next-line import/no-unresolved
+import { view, store } from 'react-easy-state';
+import {
+ BrowserRouter as Router,
+ Route,
+ Link,
+ withRouter,
+} from 'react-router-dom';
+
+describe('withRouter interaction', () => {
+ afterEach(() => {
+ cleanup();
+ window.history.replaceState({}, '', '/');
+ });
+
+ describe('function components', () => {
+ test('should be reactive with withRouter(view(Comp))', () => {
+ const counter = store({ num: 0 });
+ const MyComp = withRouter(view(() => {counter.num}
));
+
+ const { container } = render(
+
+
+ ,
+ );
+ expect(container).toHaveTextContent('0');
+ act(() => {
+ counter.num += 1;
+ });
+ expect(container).toHaveTextContent('1');
+ });
+
+ test('should properly route with withRouter(view(Comp))', () => {
+ const MyComp = withRouter(
+ view(() => (
+
+
To Settings
+
Settings
} />
+
+ )),
+ );
+
+ const { container, getByText } = render(
+
+
+ ,
+ );
+
+ expect(container.querySelector('p')).toBe(null);
+ fireEvent.click(getByText('To Settings'));
+ expect(container.querySelector('p')).toHaveTextContent(
+ 'Settings',
+ );
+ });
+ });
+
+ describe('class components', () => {
+ test('should be reactive with withRouter(view(Comp))', () => {
+ const counter = store({ num: 0 });
+ const MyComp = withRouter(
+ view(
+ class MyComp extends Component {
+ render() {
+ return {counter.num}
;
+ }
+ },
+ ),
+ );
+
+ const { container } = render(
+
+
+ ,
+ );
+ expect(container).toHaveTextContent('0');
+ act(() => {
+ counter.num += 1;
+ });
+ expect(container).toHaveTextContent('1');
+ });
+
+ test('should properly route with withRouter(view(Comp))', () => {
+ const MyComp = withRouter(
+ view(
+ class MyComp extends Component {
+ render() {
+ return (
+
+
To Settings
+
Settings
}
+ />
+
+ );
+ }
+ },
+ ),
+ );
+
+ const { container, getByText } = render(
+
+
+ ,
+ );
+
+ expect(container.querySelector('p')).toBe(null);
+ fireEvent.click(getByText('To Settings'));
+ expect(container.querySelector('p')).toHaveTextContent(
+ 'Settings',
+ );
+ });
+ });
+});
diff --git a/__tests__/staticProps.test.js b/__tests__/staticProps.test.js
index 3eb35b6..ddd9151 100644
--- a/__tests__/staticProps.test.js
+++ b/__tests__/staticProps.test.js
@@ -1,59 +1,63 @@
-import { Component } from 'react'
-import { view } from 'react-easy-state'
+/* eslint-disable react/forbid-foreign-prop-types */
+/* eslint-disable no-multi-assign */
+import { Component } from 'react';
+// eslint-disable-next-line import/no-unresolved
+import { view } from 'react-easy-state';
describe('static props', () => {
test('view() should proxy static properties from wrapped components', () => {
class Comp extends Component {}
- function FuncComp () {}
-
- Comp.displayName = FuncComp.displayName = 'Name'
- Comp.contextTypes = FuncComp.contextTypes = {}
- Comp.propTypes = FuncComp.propTypes = {}
- Comp.defaultProps = FuncComp.defaultProps = {}
- Comp.customProp = FuncComp.customProp = {}
-
- const ViewComp = view(Comp)
- const ViewFuncComp = view(FuncComp)
-
- expect(ViewComp.displayName).toBe(Comp.displayName)
- expect(ViewComp.contextTypes).toBe(Comp.contextTypes)
- expect(ViewComp.propTypes).toBe(Comp.propTypes)
- expect(ViewComp.defaultProps).toBe(Comp.defaultProps)
- expect(ViewComp.customProp).toBe(Comp.customProp)
-
- expect(ViewFuncComp.displayName).toBe(FuncComp.displayName)
- expect(ViewFuncComp.contextTypes).toBe(FuncComp.contextTypes)
- expect(ViewFuncComp.propTypes).toBe(FuncComp.propTypes)
- expect(ViewFuncComp.defaultProps).toBe(FuncComp.defaultProps)
- expect(ViewFuncComp.customProp).toBe(FuncComp.customProp)
- })
+ function FuncComp() {}
+
+ Comp.displayName = FuncComp.displayName = 'Name';
+ Comp.contextTypes = FuncComp.contextTypes = {};
+ Comp.propTypes = FuncComp.propTypes = {};
+ Comp.defaultProps = FuncComp.defaultProps = {};
+ Comp.customProp = FuncComp.customProp = {};
+
+ const ViewComp = view(Comp);
+ const ViewFuncComp = view(FuncComp);
+
+ expect(ViewComp.displayName).toBe(Comp.displayName);
+ expect(ViewComp.contextTypes).toBe(Comp.contextTypes);
+ expect(ViewComp.propTypes).toBe(Comp.propTypes);
+ expect(ViewComp.defaultProps).toBe(Comp.defaultProps);
+ expect(ViewComp.customProp).toBe(Comp.customProp);
+
+ expect(ViewFuncComp.displayName).toBe(FuncComp.displayName);
+ expect(ViewFuncComp.contextTypes).toBe(FuncComp.contextTypes);
+ expect(ViewFuncComp.propTypes).toBe(FuncComp.propTypes);
+ expect(ViewFuncComp.defaultProps).toBe(FuncComp.defaultProps);
+ expect(ViewFuncComp.customProp).toBe(FuncComp.customProp);
+ });
test('view() should proxy static methods', () => {
class Comp extends Component {
- static getDerivedStateFromError () {}
- static customMethod () {}
+ static getDerivedStateFromError() {}
+
+ static customMethod() {}
}
- const ViewComp = view(Comp)
+ const ViewComp = view(Comp);
expect(ViewComp.getDerivedStateFromError).toBe(
- Comp.getDerivedStateFromError
- )
- expect(ViewComp.customMethod).toBe(Comp.customMethod)
- })
+ Comp.getDerivedStateFromError,
+ );
+ expect(ViewComp.customMethod).toBe(Comp.customMethod);
+ });
test('view() should proxy static getters', () => {
class Comp extends Component {
- static get defaultProp () {
- return { key: 'value' }
+ static get defaultProp() {
+ return { key: 'value' };
}
- static get customProp () {
- return { key: 'hello' }
+ static get customProp() {
+ return { key: 'hello' };
}
}
- const ViewComp = view(Comp)
- expect(ViewComp.defaultProps).toEqual(Comp.defaultProps)
- expect(ViewComp.customProp).toEqual(Comp.customProp)
- })
-})
+ const ViewComp = view(Comp);
+ expect(ViewComp.defaultProps).toEqual(Comp.defaultProps);
+ expect(ViewComp.customProp).toEqual(Comp.customProp);
+ });
+});
diff --git a/__tests__/styled.test.js b/__tests__/styled.test.jsx
similarity index 57%
rename from __tests__/styled.test.js
rename to __tests__/styled.test.jsx
index 4c3e218..5503cd0 100644
--- a/__tests__/styled.test.js
+++ b/__tests__/styled.test.jsx
@@ -1,91 +1,94 @@
-import React, { Component } from 'react'
-import { render, cleanup, act } from '@testing-library/react/pure'
-import { view, store } from 'react-easy-state'
-import { withTheme, ThemeProvider } from 'styled-components'
+import React, { Component } from 'react';
+import { render, cleanup, act } from '@testing-library/react/pure';
+// eslint-disable-next-line import/no-unresolved
+import { view, store } from 'react-easy-state';
+import { withTheme, ThemeProvider } from 'styled-components';
describe('withRouter interaction', () => {
- const theme = { color: 'red' }
+ const theme = { color: 'red' };
const Theme = ({ children }) => (
{children}
- )
+ );
afterEach(() => {
- cleanup()
- })
+ cleanup();
+ });
describe('function components', () => {
test('should be reactive with withTheme(view(Comp))', () => {
- const counter = store({ num: 0 })
- const MyComp = withTheme(view(() => {counter.num}
))
+ const counter = store({ num: 0 });
+ const MyComp = withTheme(view(() => {counter.num}
));
const { container } = render(
-
- )
- expect(container).toHaveTextContent('0')
+ ,
+ );
+ expect(container).toHaveTextContent('0');
act(() => {
- counter.num++
- })
- expect(container).toHaveTextContent('1')
- })
+ counter.num += 1;
+ });
+ expect(container).toHaveTextContent('1');
+ });
test('should properly inject theme with withTheme(view(Comp))', () => {
const MyComp = withTheme(
- view(({ theme }) => Hello
)
- )
+ view(({ theme: hocTheme }) => (
+ Hello
+ )),
+ );
const { container } = render(
-
- )
- expect(container.querySelector('p')).toHaveStyle('color: red;')
- })
- })
+ ,
+ );
+ expect(container.querySelector('p')).toHaveStyle('color: red;');
+ });
+ });
describe('class components', () => {
test('should be reactive with withTheme(view(Comp))', () => {
- const counter = store({ num: 0 })
+ const counter = store({ num: 0 });
const MyComp = withTheme(
view(
class MyComp extends Component {
- render () {
- return {counter.num}
+ render() {
+ return {counter.num}
;
}
- }
- )
- )
+ },
+ ),
+ );
const { container } = render(
-
- )
- expect(container).toHaveTextContent('0')
+ ,
+ );
+ expect(container).toHaveTextContent('0');
act(() => {
- counter.num++
- })
- expect(container).toHaveTextContent('1')
- })
+ counter.num += 1;
+ });
+ expect(container).toHaveTextContent('1');
+ });
test('should properly route with withRouter(view(Comp))', () => {
const MyComp = withTheme(
view(
class MyComp extends Component {
- render () {
- return Hello
+ render() {
+ return Hello
;
}
- }
- )
- )
+ },
+ ),
+ );
const { container } = render(
-
- )
- expect(container.querySelector('p')).toHaveStyle('color: red;')
- })
- })
-})
+ ,
+ );
+ expect(container.querySelector('p')).toHaveStyle('color: red;');
+ });
+ });
+});
diff --git a/jest.native.json b/jest.native.json
index 01961dc..e4870dd 100644
--- a/jest.native.json
+++ b/jest.native.json
@@ -1,6 +1,6 @@
{
"preset": "react-native",
- "testRegex": "\\.test\\.native\\.js$",
+ "testRegex": "\\.test\\.native\\.jsx?$",
"transform": {
"^.+\\.(js|jsx)$": "react-native/jest/preprocessor.js"
},
diff --git a/jest.web.json b/jest.web.json
index 136b086..1e361f7 100644
--- a/jest.web.json
+++ b/jest.web.json
@@ -1,7 +1,7 @@
{
"setupFilesAfterEnv": ["./scripts/testSetup.js"],
"testURL": "http://react-easy-state.com",
- "testRegex": "\\.test\\.js$",
+ "testRegex": "\\.test\\.jsx?$",
"collectCoverage": true,
"coverageReporters": ["lcovonly", "text"],
"collectCoverageFrom": [
diff --git a/package-lock.json b/package-lock.json
index c488eea..2f16e36 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15370,15 +15370,6 @@
"yallist": "^2.1.2"
}
},
- "magic-string": {
- "version": "0.25.2",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.2.tgz",
- "integrity": "sha512-iLs9mPjh9IuTtRsqqhNGYcZXGei0Nh/A4xirrsqW7c+QhKVFL2vm7U09ru6cHRD22azaP/wMDgI+HCqbETMTtg==",
- "dev": true,
- "requires": {
- "sourcemap-codec": "^1.4.4"
- }
- },
"make-dir": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
@@ -17864,18 +17855,6 @@
"object-assign": "^4.1.1",
"prop-types": "^15.6.2",
"scheduler": "^0.18.0"
- },
- "dependencies": {
- "scheduler": {
- "version": "0.18.0",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.18.0.tgz",
- "integrity": "sha512-agTSHR1Nbfi6ulI0kYNK0203joW2Y5W4po4l+v03tOoiJKpTBbxpNhWDvqc/4IcOw+KLmSiQLTasZ4cab2/UWQ==",
- "dev": true,
- "requires": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1"
- }
- }
}
},
"react-is": {
@@ -18682,308 +18661,6 @@
}
}
},
- "rollup-plugin-replace": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/rollup-plugin-replace/-/rollup-plugin-replace-2.2.0.tgz",
- "integrity": "sha512-/5bxtUPkDHyBJAKketb4NfaeZjL5yLZdeUihSfbF2PQMz+rSTEb8ARKoOl3UBT4m7/X+QOXJo3sLTcq+yMMYTA==",
- "dev": true,
- "requires": {
- "magic-string": "^0.25.2",
- "rollup-pluginutils": "^2.6.0"
- },
- "dependencies": {
- "arr-diff": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
- "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
- "dev": true
- },
- "array-unique": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
- "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
- "dev": true
- },
- "braces": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
- "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
- "dev": true,
- "requires": {
- "arr-flatten": "^1.1.0",
- "array-unique": "^0.3.2",
- "extend-shallow": "^2.0.1",
- "fill-range": "^4.0.0",
- "isobject": "^3.0.1",
- "repeat-element": "^1.1.2",
- "snapdragon": "^0.8.1",
- "snapdragon-node": "^2.0.1",
- "split-string": "^3.0.2",
- "to-regex": "^3.0.1"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "dev": true,
- "requires": {
- "is-extendable": "^0.1.0"
- }
- }
- }
- },
- "estree-walker": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.0.tgz",
- "integrity": "sha512-peq1RfVAVzr3PU/jL31RaOjUKLoZJpObQWJJ+LgfcxDUifyLZ1RjPQZTl0pzj2uJ45b7A7XpyppXvxdEqzo4rw==",
- "dev": true
- },
- "expand-brackets": {
- "version": "2.1.4",
- "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
- "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
- "dev": true,
- "requires": {
- "debug": "^2.3.3",
- "define-property": "^0.2.5",
- "extend-shallow": "^2.0.1",
- "posix-character-classes": "^0.1.0",
- "regex-not": "^1.0.0",
- "snapdragon": "^0.8.1",
- "to-regex": "^3.0.1"
- },
- "dependencies": {
- "define-property": {
- "version": "0.2.5",
- "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
- "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
- "dev": true,
- "requires": {
- "is-descriptor": "^0.1.0"
- }
- },
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "dev": true,
- "requires": {
- "is-extendable": "^0.1.0"
- }
- },
- "is-accessor-descriptor": {
- "version": "0.1.6",
- "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
- "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
- "dev": true,
- "requires": {
- "kind-of": "^3.0.2"
- },
- "dependencies": {
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "dev": true,
- "requires": {
- "is-buffer": "^1.1.5"
- }
- }
- }
- },
- "is-data-descriptor": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
- "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
- "dev": true,
- "requires": {
- "kind-of": "^3.0.2"
- },
- "dependencies": {
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "dev": true,
- "requires": {
- "is-buffer": "^1.1.5"
- }
- }
- }
- },
- "is-descriptor": {
- "version": "0.1.6",
- "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
- "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
- "dev": true,
- "requires": {
- "is-accessor-descriptor": "^0.1.6",
- "is-data-descriptor": "^0.1.4",
- "kind-of": "^5.0.0"
- }
- },
- "kind-of": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
- "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
- "dev": true
- }
- }
- },
- "extglob": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
- "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
- "dev": true,
- "requires": {
- "array-unique": "^0.3.2",
- "define-property": "^1.0.0",
- "expand-brackets": "^2.1.4",
- "extend-shallow": "^2.0.1",
- "fragment-cache": "^0.2.1",
- "regex-not": "^1.0.0",
- "snapdragon": "^0.8.1",
- "to-regex": "^3.0.1"
- },
- "dependencies": {
- "define-property": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
- "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
- "dev": true,
- "requires": {
- "is-descriptor": "^1.0.0"
- }
- },
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "dev": true,
- "requires": {
- "is-extendable": "^0.1.0"
- }
- }
- }
- },
- "fill-range": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
- "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
- "dev": true,
- "requires": {
- "extend-shallow": "^2.0.1",
- "is-number": "^3.0.0",
- "repeat-string": "^1.6.1",
- "to-regex-range": "^2.1.0"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "dev": true,
- "requires": {
- "is-extendable": "^0.1.0"
- }
- }
- }
- },
- "is-accessor-descriptor": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
- "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
- "dev": true,
- "requires": {
- "kind-of": "^6.0.0"
- }
- },
- "is-data-descriptor": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
- "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
- "dev": true,
- "requires": {
- "kind-of": "^6.0.0"
- }
- },
- "is-descriptor": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
- "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
- "dev": true,
- "requires": {
- "is-accessor-descriptor": "^1.0.0",
- "is-data-descriptor": "^1.0.0",
- "kind-of": "^6.0.2"
- }
- },
- "is-number": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
- "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
- "dev": true,
- "requires": {
- "kind-of": "^3.0.2"
- },
- "dependencies": {
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "dev": true,
- "requires": {
- "is-buffer": "^1.1.5"
- }
- }
- }
- },
- "isobject": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
- "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
- "dev": true
- },
- "kind-of": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
- "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
- "dev": true
- },
- "micromatch": {
- "version": "3.1.10",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
- "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
- "dev": true,
- "requires": {
- "arr-diff": "^4.0.0",
- "array-unique": "^0.3.2",
- "braces": "^2.3.1",
- "define-property": "^2.0.2",
- "extend-shallow": "^3.0.2",
- "extglob": "^2.0.4",
- "fragment-cache": "^0.2.1",
- "kind-of": "^6.0.2",
- "nanomatch": "^1.2.9",
- "object.pick": "^1.3.0",
- "regex-not": "^1.0.0",
- "snapdragon": "^0.8.1",
- "to-regex": "^3.0.2"
- }
- },
- "rollup-pluginutils": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.7.1.tgz",
- "integrity": "sha512-3nRf3buQGR9qz/IsSzhZAJyoK663kzseps8itkYHr+Z7ESuaffEPfgRinxbCRA0pf0gzLqkNKkSb8aNVTq75NA==",
- "dev": true,
- "requires": {
- "estree-walker": "^0.6.0",
- "micromatch": "^3.1.10"
- }
- }
- }
- },
"rollup-pluginutils": {
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
@@ -19373,6 +19050,16 @@
"xmlchars": "^2.1.1"
}
},
+ "scheduler": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.18.0.tgz",
+ "integrity": "sha512-agTSHR1Nbfi6ulI0kYNK0203joW2Y5W4po4l+v03tOoiJKpTBbxpNhWDvqc/4IcOw+KLmSiQLTasZ4cab2/UWQ==",
+ "dev": true,
+ "requires": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1"
+ }
+ },
"semver": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
@@ -19772,12 +19459,6 @@
"integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
"dev": true
},
- "sourcemap-codec": {
- "version": "1.4.4",
- "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.4.tgz",
- "integrity": "sha512-CYAPYdBu34781kLHkaW3m6b/uUSyMOC2R61gcYMWooeuaGtjof86ZA/8T+qVPPt7np1085CR9hmMGrySwEc8Xg==",
- "dev": true
- },
"spawn-wrap": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz",
diff --git a/package.json b/package.json
index a8fe7c2..5526710 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,8 @@
"test-builds": "node ./scripts/testBuilds.js",
"lint": "eslint --max-warnings 0 --ext js,jsx src scripts",
"lint-fix": "eslint --max-warnings 0 --ext js,jsx src scripts --fix",
+ "lint-tests": "eslint --max-warnings 0 --ext js,jsx __tests__ __mocks__",
+ "lint-tests-fix": "eslint --max-warnings 0 --ext js,jsx __tests__ __mocks__ --fix",
"install-examples": "node ./scripts/installExamples.js",
"build-examples": "node ./scripts/buildExamples.js",
"link-examples": "node ./scripts/linkExamples.js",
@@ -97,7 +99,6 @@
"rollup-plugin-auto-external": "^2.0.0",
"rollup-plugin-babel": "^4.3.3",
"rollup-plugin-node-resolve": "^5.2.0",
- "rollup-plugin-replace": "^2.2.0",
"sinon": "^8.1.1",
"styled-components": "^5.0.1"
},
@@ -106,7 +107,7 @@
},
"husky": {
"hooks": {
- "pre-commit": "npm run lint",
+ "pre-commit": "npm run lint && npm run lint-tests",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
},
diff --git a/rollup.config.js b/rollup.config.js
index 681efc7..c4969f8 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -1,110 +1,69 @@
-import path from 'path'
-import replacePlugin from 'rollup-plugin-replace'
-import resolvePlugin from 'rollup-plugin-node-resolve'
-import babelPlugin from 'rollup-plugin-babel'
-import externalsPlugin from 'rollup-plugin-auto-external'
+import path from 'path';
+import resolvePlugin from 'rollup-plugin-node-resolve';
+import babelPlugin from 'rollup-plugin-babel';
+import externalsPlugin from 'rollup-plugin-auto-external';
export default [
- {
- input: path.resolve('src/platforms/dom.js'),
- external: ['react-dom'],
- output: [
- {
- format: 'es',
- dir: 'dist',
- entryFileNames: 'react-platform.js'
- },
- {
- format: 'cjs',
- dir: 'dist',
- entryFileNames: 'react-platform.cjs.js'
- }
- ]
- },
- {
- input: path.resolve('src/platforms/native.js'),
- external: ['react-native'],
- output: [
- {
- format: 'es',
- dir: 'dist',
- entryFileNames: 'react-platform.native.js'
- },
- {
- format: 'cjs',
- dir: 'dist',
- entryFileNames: 'react-platform.cjs.native.js'
- }
- ]
- },
{
input: path.resolve('src/index.js'),
- external: ['./react-platform'],
plugins: [
- replacePlugin({ 'react-platform': './react-platform' }),
resolvePlugin(),
babelPlugin({ exclude: 'node_modules/**' }),
- externalsPlugin({ dependencies: true, peerDependecies: true })
+ externalsPlugin({ dependencies: true, peerDependecies: true }),
],
output: {
format: 'es',
dir: 'dist',
entryFileNames: 'es.es6.js',
- sourcemap: true
- }
+ sourcemap: true,
+ },
},
{
input: path.resolve('src/index.js'),
- external: ['./react-platform'],
plugins: [
- replacePlugin({ 'react-platform': './react-platform' }),
resolvePlugin(),
babelPlugin({
exclude: 'node_modules/**',
- presets: ['@babel/preset-env']
+ presets: ['@babel/preset-env'],
}),
- externalsPlugin({ dependencies: true, peerDependecies: true })
+ externalsPlugin({ dependencies: true, peerDependecies: true }),
],
output: {
format: 'es',
dir: 'dist',
entryFileNames: 'es.es5.js',
- sourcemap: true
- }
+ sourcemap: true,
+ },
},
{
input: path.resolve('src/index.js'),
- external: ['./react-platform.cjs'],
plugins: [
- replacePlugin({ 'react-platform': './react-platform.cjs' }),
resolvePlugin(),
babelPlugin({ exclude: 'node_modules/**' }),
- externalsPlugin({ dependencies: true, peerDependecies: true })
+ externalsPlugin({ dependencies: true, peerDependecies: true }),
],
output: {
format: 'cjs',
dir: 'dist',
entryFileNames: 'cjs.es6.js',
- sourcemap: true
- }
+ sourcemap: true,
+ },
},
{
input: path.resolve('src/index.js'),
- external: ['./react-platform.cjs'],
plugins: [
- replacePlugin({ 'react-platform': './react-platform.cjs' }),
resolvePlugin(),
babelPlugin({
exclude: 'node_modules/**',
- presets: ['@babel/preset-env']
+ presets: ['@babel/preset-env'],
}),
- externalsPlugin({ dependencies: true, peerDependecies: true })
+ externalsPlugin({ dependencies: true, peerDependecies: true }),
],
output: {
format: 'cjs',
dir: 'dist',
entryFileNames: 'cjs.es5.js',
- sourcemap: true
- }
- }
-]
+ sourcemap: true,
+ },
+ },
+];
diff --git a/scripts/testBuilds.js b/scripts/testBuilds.js
index 54d6cb1..74c3bec 100644
--- a/scripts/testBuilds.js
+++ b/scripts/testBuilds.js
@@ -6,11 +6,7 @@ const { exec } = require('child_process');
const distPath = path.resolve('dist');
const files = fs
.readdirSync(distPath)
- .filter(
- dist =>
- dist.indexOf('map') === -1 &&
- dist.indexOf('react-platform') === -1,
- );
+ .filter(dist => dist.indexOf('map') === -1);
function execPromise(cmd) {
return new Promise(resolve => exec(cmd, resolve));
diff --git a/src/platforms/dom.js b/src/platforms/dom.js
deleted file mode 100644
index 2a69d4b..0000000
--- a/src/platforms/dom.js
+++ /dev/null
@@ -1 +0,0 @@
-export * from 'react-dom';
diff --git a/src/platforms/native.js b/src/platforms/native.js
deleted file mode 100644
index f58ecd3..0000000
--- a/src/platforms/native.js
+++ /dev/null
@@ -1 +0,0 @@
-export * from 'react-native';