diff --git a/.babelrc b/.babelrc index 30ec41d..7b5ba33 100644 --- a/.babelrc +++ b/.babelrc @@ -1,29 +1,43 @@ { "env": { - // Compatibility Profile. ES5 output and CommonJS module format. - "commonjs": { + // Compatibility Profile. + // ES5 output and CommonJS module format. + "es5_cjs": { "presets": [ - ["env", { - "useBuiltIns": false - }], - "react" + "@babel/preset-env", + "@babel/preset-react" ] }, - // Future Profile. ES6 output and module syntax. + // Future Profile. + // ES6 output with no module transformation (ES Modules syntax). "es": { "presets": [ - ["env", { - "useBuiltIns": false, + ["@babel/preset-env", { "modules": false, "targets": { "node": "6.5" } }], - "react" + "@babel/preset-react" + ] + }, + // Bundled Profile. + // ES5 output and UMD module format. + "umd": { + "presets": [ + ["@babel/preset-env", { + "modules": false, + }], + "@babel/preset-react" ] }, + // Jest Profile. + // To be used by jest tests. "test": { - "presets": ["env", "react"] + "presets": [ + "@babel/preset-env", + "@babel/preset-react" + ] } } } diff --git a/.gitignore b/.gitignore index 8c00fd0..8539b49 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,30 @@ -node_modules -.DS_Store -dist/ -typings/ -*.orig +# Common aux folders +.awcache/ +.vscode/ .idea/ -*/src/**/*.js.map -yarn.lock -*.log +.cache/ + +# Dependencies & Build +node_modules/ +build/ lib/ +dist/ es/ + +# Aux files +*.cer +*.log +*/src/**/*.orig +*/src/**/*.js.map + +# Win +desktop.ini + +# MacOs +.DS_Store + +# Yarn +yarn.lock + +# NPM package-lock.json diff --git a/.vscode/launch.json b/.vscode/launch.json index 4974b0e..0ba6254 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,17 +1,48 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "type": "node", - "request": "launch", - "name": "Jest single run", - "program": "${workspaceRoot}/node_modules/jest/bin/jest.js", - "args": [ - "--verbose", - "-i" - ], - "console": "integratedTerminal", - "internalConsoleOptions": "neverOpen" - }, - ] -} + +{ + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Jest single run", + "program": "${workspaceRoot}/node_modules/jest/bin/jest.js", + "args": [ + "--verbose", + "-i", + "--no-cache" + ], + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen" + }, + { + "type": "node", + "request": "launch", + "name": "Jest watch run", + "program": "${workspaceRoot}/node_modules/jest/bin/jest.js", + "args": [ + "--verbose", + "-i", + "--no-cache", + "--watchAll" + ], + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen" + }, + { + "type": "node", + "request": "launch", + "name": "Jest current file", + "program": "${workspaceRoot}/node_modules/jest/bin/jest.js", + "args": [ + "${fileBasename}", + "--verbose", + "-i", + "--no-cache", + "--watchAll" + ], + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen" + } + ] +} diff --git a/config/test/polyfills.js b/config/test/polyfills.js new file mode 100644 index 0000000..0d9f7ef --- /dev/null +++ b/config/test/polyfills.js @@ -0,0 +1,2 @@ +// Polyfill requestAnimationFrame required by React >=16.0.0 +require('raf/polyfill'); diff --git a/test/jestsetup.js b/config/test/setupJest.js similarity index 100% rename from test/jestsetup.js rename to config/test/setupJest.js diff --git a/config/webpack/helpers.js b/config/webpack/helpers.js new file mode 100644 index 0000000..f122eed --- /dev/null +++ b/config/webpack/helpers.js @@ -0,0 +1,25 @@ +const path = require('path'); + +// String helpers +const capitalizeString = s => s.charAt(0).toUpperCase() + s.slice(1); +const camelCaseString = dashedName => dashedName.split("-").map( + (s, i) => i > 0 ? capitalizeString(s) : s +).join(""); + +// Name helpers +const packageName = process.env.npm_package_name; +const packageNameCamelCase = camelCaseString(packageName); +const version = JSON.stringify(process.env.npm_package_version).replace(/"/g, ''); +const getBundleFileName = min => `${packageName}-${version}${min ? ".min" : ''}.js`; + +// Path helpers +const rootPath = path.resolve(__dirname, "../.."); +const resolveFromRootPath = (...args) => path.join(rootPath, ...args); + +// Export constants +exports.srcPath = resolveFromRootPath("src"); +exports.buildPath = resolveFromRootPath("build",); +exports.distPath = resolveFromRootPath("build", "dist"); +exports.version = version; +exports.packageNameCamelCase = packageNameCamelCase; +exports.getBundleFileName = getBundleFileName; diff --git a/config/webpack/webpack.common.js b/config/webpack/webpack.common.js new file mode 100644 index 0000000..07e04db --- /dev/null +++ b/config/webpack/webpack.common.js @@ -0,0 +1,30 @@ +const helpers = require('./helpers'); + +module.exports = (env, argv) => { + const minimizeBundle = Boolean(argv['optimize-minimize']); + + return { + entry: ['./src/index.js'], + output: { + path: helpers.distPath, + filename: helpers.getBundleFileName(minimizeBundle), + library: helpers.packageNameCamelCase, + libraryTarget: 'umd', + }, + externals: { + react: 'react', + }, + optimization: { + minimize: minimizeBundle, + }, + module: { + rules: [ + { + test: /\.js$/, + exclude: /node_modules/, + loader: 'babel-loader', + }, + ], + }, + }; +}; diff --git a/config/webpack/webpack.dev.js b/config/webpack/webpack.dev.js new file mode 100644 index 0000000..864751c --- /dev/null +++ b/config/webpack/webpack.dev.js @@ -0,0 +1,7 @@ +const merge = require('webpack-merge'); +const commonConfig = require('./webpack.common.js'); + +module.exports = (env, argv) => merge(commonConfig(env, argv), { + mode: 'development', + devtool: 'inline-source-map', +}); diff --git a/config/webpack/webpack.prod.js b/config/webpack/webpack.prod.js new file mode 100644 index 0000000..52f6ed1 --- /dev/null +++ b/config/webpack/webpack.prod.js @@ -0,0 +1,17 @@ +const merge = require('webpack-merge'); +const commonConfig = require('./webpack.common.js'); +const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin; +const CompressionPlugin = require('compression-webpack-plugin'); + +module.exports = (env, argv) => merge(commonConfig(env, argv), { + mode: 'production', + devtool: 'none', + plugins: [ + new BundleAnalyzerPlugin({ + analyzerMode: "static", + openAnalyzer: false, + reportFilename: "report/report.html", + }), + new CompressionPlugin(), + ], +}); diff --git a/examples/00-example-basic/.babelrc b/examples/00-example-basic/.babelrc new file mode 100644 index 0000000..ae31d35 --- /dev/null +++ b/examples/00-example-basic/.babelrc @@ -0,0 +1,11 @@ +{ + "presets": [ + "@babel/preset-react", + [ + "@babel/preset-env", + { + "useBuiltIns": "entry" + } + ] + ] +} diff --git a/examples/00-example-basic/package.json b/examples/00-example-basic/package.json new file mode 100644 index 0000000..a6c9c3c --- /dev/null +++ b/examples/00-example-basic/package.json @@ -0,0 +1,34 @@ +{ + "name": "webpack-by-example", + "version": "1.0.0", + "description": "In this sample we are going to setup a web project that can be easily managed\r by webpack.", + "main": "index.js", + "scripts": { + "start": "webpack-dev-server --mode development --open", + "build": "rimraf dist && webpack --mode development", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "@babel/cli": "^7.2.3", + "@babel/core": "^7.4.0", + "@babel/preset-env": "^7.4.0", + "@babel/preset-react": "^7.0.0", + "babel-loader": "^8.0.5", + "css-loader": "^2.1.1", + "html-webpack-plugin": "^3.2.0", + "mini-css-extract-plugin": "^0.5.0", + "rimraf": "^2.6.3", + "style-loader": "^0.23.1", + "webpack": "^4.29.6", + "webpack-cli": "^3.3.0", + "webpack-dev-server": "^3.2.1" + }, + "dependencies": { + "react": "^16.8.4", + "react-dom": "^16.8.4", + "react-loader-spinner": "^2.3.0", + "react-promise-tracker": "file:../../build" + } +} diff --git a/examples/00-example-basic/src/api/fetch.js b/examples/00-example-basic/src/api/fetch.js new file mode 100644 index 0000000..93dcfb0 --- /dev/null +++ b/examples/00-example-basic/src/api/fetch.js @@ -0,0 +1,12 @@ +export const fetchWithDelay = (url) => { + const promise = new Promise((resolve, reject) => { + setTimeout(() => { + resolve(fetch(url, { + method: 'GET', + }) + .then((response) => response.json())); + }, 3000) + }); + + return promise; +} \ No newline at end of file diff --git a/examples/00-example-basic/src/api/postAPI.js b/examples/00-example-basic/src/api/postAPI.js new file mode 100644 index 0000000..3831918 --- /dev/null +++ b/examples/00-example-basic/src/api/postAPI.js @@ -0,0 +1,9 @@ +import { fetchWithDelay } from './fetch'; +const url = 'https://jsonplaceholder.typicode.com/posts'; + +const fetchPosts = () => fetchWithDelay(url) + .then((posts) => posts.slice(0, 10)); + +export const postAPI = { + fetchPosts, +}; \ No newline at end of file diff --git a/examples/00-example-basic/src/api/userAPI.js b/examples/00-example-basic/src/api/userAPI.js new file mode 100644 index 0000000..17274bd --- /dev/null +++ b/examples/00-example-basic/src/api/userAPI.js @@ -0,0 +1,8 @@ +import { fetchWithDelay } from './fetch'; +const url = 'https://jsonplaceholder.typicode.com/users'; + +const fetchUsers = () => fetchWithDelay(url); + +export const userAPI = { + fetchUsers, +}; \ No newline at end of file diff --git a/examples/00-example-basic/src/app.css b/examples/00-example-basic/src/app.css new file mode 100644 index 0000000..db650a3 --- /dev/null +++ b/examples/00-example-basic/src/app.css @@ -0,0 +1,11 @@ +.tables { + display: flex; + flex-direction: row; + flex-wrap: nowrap; +} + +.tables > div { + flex-basis: 50%; + margin-left: 1rem; + margin-right: 1rem; +} \ No newline at end of file diff --git a/examples/00-example-basic/src/app.js b/examples/00-example-basic/src/app.js new file mode 100644 index 0000000..85a42cd --- /dev/null +++ b/examples/00-example-basic/src/app.js @@ -0,0 +1,59 @@ +import React, { Component } from 'react'; +import { trackPromise } from 'react-promise-tracker'; +import { userAPI } from './api/userAPI'; +import { postAPI } from './api/postAPI'; +import { UserTable, PostTable, LoadButton } from './components'; +import './app.css'; + +export class App extends Component { + constructor() { + super(); + + this.state = { + users: [], + posts: [], + }; + + this.onLoadTables = this.onLoadTables.bind(this); + } + + onLoadTables() { + this.setState({ + users: [], + posts: [], + }); + + trackPromise( + userAPI.fetchUsers() + .then((users) => { + this.setState({ + users, + }) + }) + ); + + trackPromise( + postAPI.fetchPosts() + .then((posts) => { + this.setState({ + posts, + }) + }) + ); + } + + render() { + return ( +
(component: React.ComponentType
): React.ComponentType
;
+
+/**
+ * React Promise Tracker custom hook, this hook will expose a promiseInProgress boolean flag.
+ *
+ * @param configuration (optional can be null).
+ * @returns promiseInProgressFlag.
+ */
+export function usePromiseTracker(outerConfig? : Config) : { promiseInProgress : boolean };
diff --git a/src/index.js b/src/index.js
index 077eb9e..befeaf0 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,2 +1,3 @@
export { trackPromise } from './trackPromise';
export { promiseTrackerHoc } from './trackerHoc';
+export { usePromiseTracker } from './trackerHook';
diff --git a/src/setupConfig.js b/src/setupConfig.js
new file mode 100644
index 0000000..9e3bce9
--- /dev/null
+++ b/src/setupConfig.js
@@ -0,0 +1,9 @@
+import { defaultArea } from "./constants";
+
+export const defaultConfig = { area: defaultArea, delay: 0 };
+
+// Defensive config setup, fulfill default values
+export const setupConfig = (outerConfig) => ({
+ area: (!outerConfig || !outerConfig.area) ? defaultArea : outerConfig.area,
+ delay: (!outerConfig || !outerConfig.delay) ? 0 : outerConfig.delay,
+})
diff --git a/src/setupConfig.test.js b/src/setupConfig.test.js
new file mode 100644
index 0000000..a967159
--- /dev/null
+++ b/src/setupConfig.test.js
@@ -0,0 +1,94 @@
+import { defaultArea } from "./constants";
+import {setupConfig} from './setupConfig';
+
+describe("setupConfig", () => {
+ it("should return same config as param if all values are informed", () => {
+ // Arrange
+ const userConfig = {area: 'myarea', delay: 200};
+ // Act
+ const result = setupConfig(userConfig);
+
+ // Assert
+ expect(result.area).toBe('myarea');
+ expect(result.delay).toBe(200);
+ });
+
+ it("should return default config (default are, 0 delay) if input param is undefined", () => {
+ // Arrange
+ const userConfig = void(0);
+ // Act
+ const result = setupConfig(userConfig);
+
+ // Assert
+ expect(result.area).toBe(defaultArea);
+ expect(result.delay).toBe(0);
+ });
+
+ it("should return default config (default area, 0 delay) if input para is null", () => {
+ // Arrange
+ const userConfig = null;
+ // Act
+ const result = setupConfig(userConfig);
+
+ // Assert
+ expect(result.area).toBe(defaultArea);
+ expect(result.delay).toBe(0);
+ });
+
+ it("should fullfill default config and area if input param informed but empty object {}", () => {
+ // Arrange
+ const userConfig = null;
+ // Act
+ const result = setupConfig(userConfig);
+
+ // Assert
+ expect(result.area).toBe(defaultArea);
+ expect(result.delay).toBe(0);
+ });
+
+
+ it("should fullfill defaultArea param if undefined but delay informed", () => {
+ // Arrange
+ const userConfig = {area: void(0), delay: 200};
+ // Act
+ const result = setupConfig(userConfig);
+
+ // Assert
+ expect(result.area).toBe(defaultArea);
+ expect(result.delay).toBe(200);
+ });
+
+ it("should fullfill defaultArea param if null but delay informed", () => {
+ // Arrange
+ const userConfig = {area: null, delay: 200};
+ // Act
+ const result = setupConfig(userConfig);
+
+ // Assert
+ expect(result.area).toBe(defaultArea);
+ expect(result.delay).toBe(200);
+ });
+
+ it("should fullfill delay param (0) if undefined but area informed", () => {
+ // Arrange
+ const userConfig = {area: 'myarea', delay: void(0)};
+ // Act
+ const result = setupConfig(userConfig);
+
+ // Assert
+ expect(result.area).toBe('myarea');
+ expect(result.delay).toBe(0);
+ });
+
+ it("should fullfill delay param (0) if null but area informed", () => {
+ // Arrange
+ const userConfig = {area: 'myarea', delay: null};
+ // Act
+ const result = setupConfig(userConfig);
+
+ // Assert
+ expect(result.area).toBe('myarea');
+ expect(result.delay).toBe(0);
+ });
+
+});
diff --git a/src/trackPromise.js b/src/trackPromise.js
index 123195d..a461700 100644
--- a/src/trackPromise.js
+++ b/src/trackPromise.js
@@ -1,14 +1,14 @@
-import { Emitter } from './tinyEmmiter';
-import { defaultArea } from './constants';
+import { Emitter } from "./tinyEmmiter";
+import { defaultArea } from "./constants";
export const emitter = new Emitter();
-export const promiseCounterUpdateEventId = 'promise-counter-update';
+export const promiseCounterUpdateEventId = "promise-counter-update";
let counter = {
- [defaultArea]: 0,
+ [defaultArea]: 0
};
-export const getCounter = (area) => counter[area];
+export const getCounter = area => counter[area];
export const trackPromise = (promise, area) => {
area = area || defaultArea;
@@ -23,7 +23,7 @@ export const trackPromise = (promise, area) => {
return promise;
};
-const incrementCounter = (area) => {
+const incrementCounter = area => {
if (Boolean(counter[area])) {
counter[area]++;
} else {
@@ -31,15 +31,15 @@ const incrementCounter = (area) => {
}
};
-const anyPromiseInProgress = (area) => (counter[area] > 0);
+const anyPromiseInProgress = area => counter[area] > 0;
-const decrementPromiseCounter = (area) => {
+const decrementPromiseCounter = area => {
decrementCounter(area);
- const promiseInProgress = anyPromiseInProgress();
+ const promiseInProgress = anyPromiseInProgress(area);
emitter.emit(promiseCounterUpdateEventId, promiseInProgress, area);
};
-const decrementCounter = (area) => {
+const decrementCounter = area => {
counter[area]--;
};
diff --git a/src/trackPromise.test.js b/src/trackPromise.test.js
index d939938..df9ed51 100644
--- a/src/trackPromise.test.js
+++ b/src/trackPromise.test.js
@@ -1,9 +1,9 @@
-import { trackPromise, emitter } from './trackPromise';
-import { defaultArea } from './constants';
+import { trackPromise, emitter } from "./trackPromise";
+import { defaultArea } from "./constants";
-describe('trackPromise', () => {
- describe('using default area', () => {
- it('On Initial case, promise fired, promise emitter.emit is called', () => {
+describe("trackPromise", () => {
+ describe("using default area", () => {
+ it("On Initial case, promise fired, promise emitter.emit is called", () => {
// Arrange
emitter.emit = jest.fn();
@@ -15,10 +15,14 @@ describe('trackPromise', () => {
// Assert
expect(emitter.emit).toHaveBeenCalledTimes(1);
- expect(emitter.emit).toHaveBeenCalledWith('promise-counter-update', true, defaultArea);
+ expect(emitter.emit).toHaveBeenCalledWith(
+ "promise-counter-update",
+ true,
+ defaultArea
+ );
});
- it('Promise tracked, we got resolve, check that emit is called 2 times', (done) => {
+ it("Promise tracked, we got resolve, check that emit is called 2 times", done => {
// Arrange
emitter.emit = jest.fn();
@@ -31,14 +35,24 @@ describe('trackPromise', () => {
myPromise.then(() => {
expect(emitter.emit).toHaveBeenCalledTimes(2);
- expect(emitter.emit).toHaveBeenNthCalledWith(1, 'promise-counter-update', true, defaultArea);
-
- expect(emitter.emit).toHaveBeenNthCalledWith(2, 'promise-counter-update', false, defaultArea);
+ expect(emitter.emit).toHaveBeenNthCalledWith(
+ 1,
+ "promise-counter-update",
+ true,
+ defaultArea
+ );
+
+ expect(emitter.emit).toHaveBeenNthCalledWith(
+ 2,
+ "promise-counter-update",
+ false,
+ defaultArea
+ );
done();
});
});
- it('Promise tracked, we got fail, check that emit is called 2 times', (done) => {
+ it("Promise tracked, we got fail, check that emit is called 2 times", done => {
// Arrange
emitter.emit = jest.fn();
@@ -51,16 +65,25 @@ describe('trackPromise', () => {
myPromise.catch(() => {
expect(emitter.emit).toHaveBeenCalledTimes(2);
- expect(emitter.emit).toHaveBeenNthCalledWith(1, 'promise-counter-update', true, defaultArea);
-
- expect(emitter.emit).toHaveBeenNthCalledWith(2, 'promise-counter-update', false, defaultArea);
+ expect(emitter.emit).toHaveBeenNthCalledWith(
+ 1,
+ "promise-counter-update",
+ true,
+ defaultArea
+ );
+
+ expect(emitter.emit).toHaveBeenNthCalledWith(
+ 2,
+ "promise-counter-update",
+ false,
+ defaultArea
+ );
done();
});
});
-
// Pending promise failed
- it('Two Promises tracked, we got resolve on both, check that emit is called 4 times', (done) => {
+ it("Two Promises tracked, we got resolve on both, check that emit is called 4 times", done => {
// Arrange
emitter.emit = jest.fn();
@@ -76,19 +99,39 @@ describe('trackPromise', () => {
Promise.all(promises).then(() => {
expect(emitter.emit).toHaveBeenCalledTimes(4);
- expect(emitter.emit).toHaveBeenNthCalledWith(1, 'promise-counter-update', true, defaultArea);
-
- expect(emitter.emit).toHaveBeenNthCalledWith(2, 'promise-counter-update', true, defaultArea);
-
- expect(emitter.emit).toHaveBeenNthCalledWith(3, 'promise-counter-update', false, defaultArea);
-
- expect(emitter.emit).toHaveBeenNthCalledWith(4, 'promise-counter-update', false, defaultArea);
+ expect(emitter.emit).toHaveBeenNthCalledWith(
+ 1,
+ "promise-counter-update",
+ true,
+ defaultArea
+ );
+
+ expect(emitter.emit).toHaveBeenNthCalledWith(
+ 2,
+ "promise-counter-update",
+ true,
+ defaultArea
+ );
+
+ expect(emitter.emit).toHaveBeenNthCalledWith(
+ 3,
+ "promise-counter-update",
+ true,
+ defaultArea
+ );
+
+ expect(emitter.emit).toHaveBeenNthCalledWith(
+ 4,
+ "promise-counter-update",
+ false,
+ defaultArea
+ );
done();
});
});
// Promise chaining working properly.
- it('Promise returned must handle transparently the result when resolved', (done) => {
+ it("Promise returned must handle transparently the result when resolved", done => {
// Arrange
const expectedPromiseResult = "promise result";
const promise = Promise.resolve(expectedPromiseResult);
@@ -97,16 +140,15 @@ describe('trackPromise', () => {
const trackedPromise = trackPromise(promise);
// Assert
- trackedPromise.then((trackedPromiseResult) => {
+ trackedPromise.then(trackedPromiseResult => {
expect(trackedPromiseResult).toEqual(expectedPromiseResult);
done();
});
});
-
});
- describe('using custom area', () => {
- it('should call emitter.emit one time when feeding promise and area equals undefined', () => {
+ describe("using custom area", () => {
+ it("should call emitter.emit one time when feeding promise and area equals undefined", () => {
// Arrange
emitter.emit = jest.fn();
@@ -118,10 +160,14 @@ describe('trackPromise', () => {
// Assert
expect(emitter.emit).toHaveBeenCalledTimes(1);
- expect(emitter.emit).toHaveBeenCalledWith('promise-counter-update', true, defaultArea);
+ expect(emitter.emit).toHaveBeenCalledWith(
+ "promise-counter-update",
+ true,
+ defaultArea
+ );
});
- it('should call emitter.emit one time when feeding promise and area equals null', () => {
+ it("should call emitter.emit one time when feeding promise and area equals null", () => {
// Arrange
emitter.emit = jest.fn();
@@ -133,32 +179,40 @@ describe('trackPromise', () => {
// Assert
expect(emitter.emit).toHaveBeenCalledTimes(1);
- expect(emitter.emit).toHaveBeenCalledWith('promise-counter-update', true, defaultArea);
+ expect(emitter.emit).toHaveBeenCalledWith(
+ "promise-counter-update",
+ true,
+ defaultArea
+ );
});
- it('should call emitter.emit one time when feeding promise and area equals testArea', () => {
+ it("should call emitter.emit one time when feeding promise and area equals testArea", () => {
// Arrange
emitter.emit = jest.fn();
const myPromise = Promise.resolve();
- const area = 'testArea';
+ const area = "testArea";
// Act
trackPromise(myPromise, area);
// Assert
expect(emitter.emit).toHaveBeenCalledTimes(1);
- expect(emitter.emit).toHaveBeenCalledWith('promise-counter-update', true, 'testArea');
+ expect(emitter.emit).toHaveBeenCalledWith(
+ "promise-counter-update",
+ true,
+ "testArea"
+ );
});
- it('should call emitter.emit two times when feeding two promises in same area', () => {
+ it("should call emitter.emit two times when feeding two promises in same area", () => {
// Arrange
emitter.emit = jest.fn();
const myPromise1 = Promise.resolve();
const myPromise2 = Promise.resolve();
- const area = 'testArea';
+ const area = "testArea";
// Act
trackPromise(myPromise1, area);
@@ -166,19 +220,29 @@ describe('trackPromise', () => {
// Assert
expect(emitter.emit).toHaveBeenCalledTimes(2);
- expect(emitter.emit).toHaveBeenNthCalledWith(1, 'promise-counter-update', true, 'testArea');
- expect(emitter.emit).toHaveBeenNthCalledWith(2, 'promise-counter-update', true, 'testArea');
+ expect(emitter.emit).toHaveBeenNthCalledWith(
+ 1,
+ "promise-counter-update",
+ true,
+ "testArea"
+ );
+ expect(emitter.emit).toHaveBeenNthCalledWith(
+ 2,
+ "promise-counter-update",
+ true,
+ "testArea"
+ );
});
- it('should call emitter.emit two times when feeding two promises in different areas', () => {
+ it("should call emitter.emit two times when feeding two promises in different areas", () => {
// Arrange
emitter.emit = jest.fn();
const myPromise1 = Promise.resolve();
const myPromise2 = Promise.resolve();
- const area1 = 'testArea1';
- const area2 = 'testArea2';
+ const area1 = "testArea1";
+ const area2 = "testArea2";
// Act
trackPromise(myPromise1, area1);
@@ -186,9 +250,18 @@ describe('trackPromise', () => {
// Assert
expect(emitter.emit).toHaveBeenCalledTimes(2);
- expect(emitter.emit).toHaveBeenNthCalledWith(1, 'promise-counter-update', true, 'testArea1');
- expect(emitter.emit).toHaveBeenNthCalledWith(2, 'promise-counter-update', true, 'testArea2');
+ expect(emitter.emit).toHaveBeenNthCalledWith(
+ 1,
+ "promise-counter-update",
+ true,
+ "testArea1"
+ );
+ expect(emitter.emit).toHaveBeenNthCalledWith(
+ 2,
+ "promise-counter-update",
+ true,
+ "testArea2"
+ );
});
});
});
-
diff --git a/src/trackerHoc.js b/src/trackerHoc.js
index dfe0aac..496e56a 100644
--- a/src/trackerHoc.js
+++ b/src/trackerHoc.js
@@ -1,49 +1,79 @@
-import React, { Component } from 'react'
-import { emitter, getCounter, promiseCounterUpdateEventId } from './trackPromise';
-import { defaultArea } from './constants';
-
-export const promiseTrackerHoc = (ComponentToWrap) => {
- return class promiseTrackerComponent extends Component {
- constructor(props) {
- super(props);
-
- this.state = {
- trackedPromiseInProgress: false,
- area: props.area || defaultArea,
- };
- }
-
- updateProgress(progress, afterUpdateCallback) {
- this.setState({ trackedPromiseInProgress: progress }, afterUpdateCallback);
- }
-
- subscribeToCounterUpdate() {
- emitter.on(promiseCounterUpdateEventId, (anyPromiseInProgress, area) => {
- if (this.state.area === area) {
- this.updateProgress(anyPromiseInProgress);
- }
- });
- }
-
- componentDidMount() {
- this.updateProgress(
- Boolean(getCounter(this.state.area) > 0),
- this.subscribeToCounterUpdate
- );
- }
-
- componentWillUnmount() {
- emitter.off(promiseCounterUpdateEventId);
- }
-
- render() {
- return (
-