Skip to content

Commit

Permalink
Merge pull request #19 from yusufshakeel/dev
Browse files Browse the repository at this point in the history
v0.8.6
  • Loading branch information
yusufshakeel committed Oct 4, 2020
2 parents 75e5f85 + 802afde commit 0f99db8
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 26 deletions.
66 changes: 65 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
This is a simple coupon creation project using NodeJS.

[![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/yusufshakeel/couponjs)
[![npm version](https://img.shields.io/badge/npm-0.8.5-blue.svg)](https://www.npmjs.com/package/couponjs)
[![npm version](https://img.shields.io/badge/npm-0.8.6-blue.svg)](https://www.npmjs.com/package/couponjs)
[![Build Status](https://travis-ci.com/yusufshakeel/couponjs.svg?branch=master)](https://travis-ci.com/yusufshakeel/couponjs)
[![Coverage Status](https://coveralls.io/repos/github/yusufshakeel/couponjs/badge.svg?branch=master)](https://coveralls.io/github/yusufshakeel/couponjs?branch=master)

Expand All @@ -23,6 +23,7 @@ const CouponJS = require('couponjs');
* [Getting Started](#getting-started)
* [Coupon engine configuration](#coupon-engine-configuration)
* [Verbose](#verbose)
* [Log Performance](#log-performance)
* [Generate coupon](#generate-coupon)
* [Configuration to generate coupons](#configuration-to-generate-coupons)
* [Coupon of length N](#coupon-of-length-n)
Expand Down Expand Up @@ -93,6 +94,69 @@ And error response will look like the following.
}
```

### Log Performance

To log the performance we have to set the option `logPerformance` to `true`.

Default value: `false`

Depends on: [verbose](#verbose) to be `true`.

Syntax:

```javascript
const coupon = new CouponJS({
verbose: true,
logPerformance: true
});
```

This will return success response like the following.

```
{
"status": "success",
"numberOfCoupons": 1,
"coupons": [
"QWERTY"
],
"performance": {
"duration": {
"nano": 730779,
"micro": 730.779,
"milli": 0.730779,
"second": 0.000730779
}
}
}
```

And error response like the following.

```
{
"status": "error",
"error": {
"message": "Invalid characters used in the format rule.",
"type": "COUPONJS_VALIDATION_ERROR",
"errors": [
{
"type": "COUPONJS_FORMAT_ERROR",
"field": "format",
"message": "Invalid characters used in the format rule. Only x and - are allowed. And only one - inbetween like xxx-xxx."
}
]
},
"performance": {
"duration": {
"nano": 1313840,
"micro": 1313.84,
"milli": 1.31384,
"second": 0.00131384
}
}
}
```

## Generate coupon
Create an object.
Expand Down
3 changes: 2 additions & 1 deletion app/option.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ const {

module.exports = {
defaultCouponEngineOption: {
verbose: false
verbose: false,
logPerformance: false
},
defaultCouponGenerationOption: {
length: DEFAULT_LENGTH,
Expand Down
30 changes: 30 additions & 0 deletions app/performance.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict';

const NS_PER_SEC = 1e9;

function Performance() {
let startedAt = 0;
let duration = 0;

this.startTimer = () => {
startedAt = process.hrtime();
};

this.stopTimer = () => {
duration = process.hrtime(startedAt);
};

this.stats = () => {
const nano = duration[0] * NS_PER_SEC + duration[1];
return {
duration: {
nano,
micro: nano / 1e3,
milli: nano / 1e6,
second: nano / 1e9
}
};
};
}

module.exports = Performance;
13 changes: 11 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
const Engine = require('./app/engine.js');
const { defaultCouponGenerationOption, defaultCouponEngineOption } = require('./app/option.js');
const randomInteger = require('./app/random-integer.js');
const Performance = require('./app/performance.js');

/**
* The Coupon constructor.
* @param {object} config This is to configure the coupon engine.
* @constructor
*/
const Coupon = function (config) {
const { verbose } = Object.assign({}, defaultCouponEngineOption, config);
const performance = new Performance();
const { verbose, logPerformance } = Object.assign({}, defaultCouponEngineOption, config);

/**
* This will generate coupons.
Expand All @@ -19,6 +21,7 @@ const Coupon = function (config) {
* @returns {string}
*/
this.generate = function (option) {
performance.startTimer();
const {
numberOfCoupons,
length,
Expand All @@ -40,21 +43,27 @@ const Coupon = function (config) {
format
);
const generatedCoupons = engine.run();
performance.stopTimer();
const performanceStats = logPerformance ? { performance: performance.stats() } : {};
const verboseResult = {
...performanceStats,
numberOfCoupons,
status: 'success',
coupons: numberOfCoupons === 1 ? [generatedCoupons] : generatedCoupons
};
return verbose ? verboseResult : generatedCoupons;
} catch (e) {
performance.stopTimer();
const performanceStats = logPerformance ? { performance: performance.stats() } : {};
if (verbose) {
return {
status: 'error',
error: {
message: e.message,
type: e.type,
errors: e.errors
}
},
...performanceStats
};
} else {
throw e;
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "couponjs",
"version": "0.8.5",
"version": "0.8.6",
"description": "This is a simple coupon creation project using NodeJS.",
"main": "index.js",
"scripts": {
Expand Down
12 changes: 12 additions & 0 deletions tests/app/performance.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
'use strict';

const Performance = require('../../app/performance.js');

test('Should be able to return stats', () => {
const performance = new Performance();
performance.startTimer();
performance.stopTimer();
const result = performance.stats();
expect(Object.keys(result)).toStrictEqual(['duration']);
expect(Object.keys(result.duration)).toStrictEqual(['nano', 'micro', 'milli', 'second']);
});
82 changes: 62 additions & 20 deletions tests/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,64 @@
const Coupon = require('../index.js');

describe('Coupon engine configuration', () => {
test('Should return verbose response', () => {
const coupon = new Coupon({ verbose: true });
const result = coupon.generate();
expect(result.status).toBe('success');
expect(result.numberOfCoupons).toBe(1);
expect(/^[A-Z]{6}$/.test(result.coupons[0])).toBeTruthy();
});
describe('verbose tests', () => {
test('Should return verbose response', () => {
const coupon = new Coupon({ verbose: true });
const result = coupon.generate();
expect(result.status).toBe('success');
expect(result.numberOfCoupons).toBe(1);
expect(/^[A-Z]{6}$/.test(result.coupons[0])).toBeTruthy();
});

test('Should return verbose response - multiple coupons', () => {
const coupon = new Coupon({ verbose: true });
const result = coupon.generate({ numberOfCoupons: 2 });
expect(result.status).toBe('success');
expect(result.numberOfCoupons).toBe(2);
result.coupons.forEach(c => expect(/^[A-Z]{6}$/.test(c)).toBeTruthy());
});

test('Should return verbose response - multiple coupons', () => {
const coupon = new Coupon({ verbose: true });
const result = coupon.generate({ numberOfCoupons: 2 });
expect(result.status).toBe('success');
expect(result.numberOfCoupons).toBe(2);
result.coupons.forEach(c => expect(/^[A-Z]{6}$/.test(c)).toBeTruthy());
test('Should return verbose validation error', () => {
const coupon = new Coupon({ verbose: true });
const result = coupon.generate({ format: 'abc-xyz' });
expect(result).toStrictEqual({
status: 'error',
error: {
type: 'COUPONJS_VALIDATION_ERROR',
message: 'Invalid characters used in the format rule.',
errors: [
{
field: 'format',
message:
'Invalid characters used in the format rule. Only x and - are allowed. And only one - inbetween like xxx-xxx.',
type: 'COUPONJS_FORMAT_ERROR'
}
]
}
});
});
});

test('Should return verbose validation error', () => {
const coupon = new Coupon({ verbose: true });
const result = coupon.generate({ format: 'abc-xyz' });
expect(result).toStrictEqual({
status: 'error',
error: {
describe('performance test', () => {
test('Should log performance', () => {
const coupon = new Coupon({ verbose: true, logPerformance: true });
const result = coupon.generate();
expect(result.status).toBe('success');
expect(result.numberOfCoupons).toBe(1);
expect(/^[A-Z]{6}$/.test(result.coupons[0])).toBeTruthy();
expect(result.performance).not.toBeUndefined();
expect(result.performance.duration).not.toBeUndefined();
expect(result.performance.duration.nano).not.toBeUndefined();
expect(result.performance.duration.micro).not.toBeUndefined();
expect(result.performance.duration.milli).not.toBeUndefined();
expect(result.performance.duration.second).not.toBeUndefined();
});

test('Should return verbose validation error and also log performance', () => {
const coupon = new Coupon({ verbose: true, logPerformance: true });
const result = coupon.generate({ format: 'abc-xyz' });
expect(result.status).toBe('error');
expect(result.error).toStrictEqual({
type: 'COUPONJS_VALIDATION_ERROR',
message: 'Invalid characters used in the format rule.',
errors: [
Expand All @@ -35,7 +71,13 @@ describe('Coupon engine configuration', () => {
type: 'COUPONJS_FORMAT_ERROR'
}
]
}
});
expect(result.performance).not.toBeUndefined();
expect(result.performance.duration).not.toBeUndefined();
expect(result.performance.duration.nano).not.toBeUndefined();
expect(result.performance.duration.micro).not.toBeUndefined();
expect(result.performance.duration.milli).not.toBeUndefined();
expect(result.performance.duration.second).not.toBeUndefined();
});
});
});
Expand Down

0 comments on commit 0f99db8

Please sign in to comment.