diff --git a/.eslintrc.json b/.eslintrc.json
index 6bbed5c..76771f5 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -10,11 +10,21 @@
"no-nested-ternary": "off",
"no-param-reassign": "off",
"func-names": "off",
- "max-classes-per-file": "off"
+ "max-classes-per-file": "off",
+ "react/prefer-stateless-function": "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-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/__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..2fc3de3
--- /dev/null
+++ b/__tests__/edgeCases.test.jsx
@@ -0,0 +1,261 @@
+/* eslint-disable react/destructuring-assignment */
+/* eslint-disable react/state-in-constructor */
+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.json b/package.json
index 06b181c..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",
@@ -105,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"
}
},