From 3d12b0f2ba486bc66ef230999f1acda7eb075761 Mon Sep 17 00:00:00 2001 From: Krist Wongsuphasawat Date: Fri, 16 Nov 2018 21:55:46 -0800 Subject: [PATCH] Add @superset-ui/number-format package (#31) * feat: Add number-format package --- .../superset-ui/README.md | 3 +- .../superset-ui-number-format/README.md | 57 +++++++++++++++++ .../superset-ui-number-format/package.json | 33 ++++++++++ .../src/NumberFormats.js | 31 +++++++++ .../src/NumberFormatter.js | 35 ++++++++++ .../src/NumberFormatterRegistry.js | 32 ++++++++++ .../src/NumberFormatterRegistrySingleton.js | 14 ++++ .../src/formatters/D3Formatter.js | 40 ++++++++++++ .../src/formatters/SiAtMostNDigitFormatter.js | 19 ++++++ .../superset-ui-number-format/src/index.js | 10 +++ .../test/NumberFormatter.test.js | 64 +++++++++++++++++++ .../test/NumberFormatterRegistry.test.js | 32 ++++++++++ .../NumberFormatterRegistrySingleton.test.js | 29 +++++++++ .../test/formatters/D3Formatter.test.js | 28 ++++++++ .../SiAtMostNDigitFormatter.test.js | 51 +++++++++++++++ .../test/index.test.js | 21 ++++++ 16 files changed, 498 insertions(+), 1 deletion(-) create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/README.md create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/package.json create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/NumberFormats.js create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/NumberFormatter.js create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/NumberFormatterRegistry.js create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/NumberFormatterRegistrySingleton.js create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/formatters/D3Formatter.js create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/formatters/SiAtMostNDigitFormatter.js create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/index.js create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/NumberFormatter.test.js create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/NumberFormatterRegistry.test.js create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/NumberFormatterRegistrySingleton.test.js create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/formatters/D3Formatter.test.js create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/formatters/SiAtMostNDigitFormatter.test.js create mode 100644 superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/index.test.js diff --git a/superset-frontend/temporary_superset_ui/superset-ui/README.md b/superset-frontend/temporary_superset_ui/superset-ui/README.md index d49c4f8f0fee..48791aacbad4 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/README.md +++ b/superset-frontend/temporary_superset_ui/superset-ui/README.md @@ -15,6 +15,8 @@ applications that leverage a Superset backend :chart_with_upwards_trend: | [@superset-ui/color](https://github.com/apache-superset/superset-ui/tree/master/packages/superset-ui-color) | [![Version](https://img.shields.io/npm/v/@superset-ui/color.svg?style=flat-square)](https://img.shields.io/npm/v/@superset-ui/color.svg?style=flat-square) | | [@superset-ui/connection](https://github.com/apache-superset/superset-ui/tree/master/packages/superset-ui-connection) | [![Version](https://img.shields.io/npm/v/@superset-ui/connection.svg?style=flat-square)](https://img.shields.io/npm/v/@superset-ui/connection.svg?style=flat-square) | | [@superset-ui/core](https://github.com/apache-superset/superset-ui/tree/master/packages/superset-ui-core) | [![Version](https://img.shields.io/npm/v/@superset-ui/core.svg?style=flat-square)](https://img.shields.io/npm/v/@superset-ui/core.svg?style=flat-square) | +| [@superset-ui/generator-superset](https://github.com/apache-superset/superset-ui/tree/master/packages/superset-ui-generator-superset) | [![Version](https://img.shields.io/npm/v/@superset-ui/generator-superset.svg?style=flat-square)](https://img.shields.io/npm/v/@superset-ui/generator-superset.svg?style=flat-square) | +| [@superset-ui/number-format](https://github.com/apache-superset/superset-ui/tree/master/packages/superset-ui-number-format) | [![Version](https://img.shields.io/npm/v/@superset-ui/number-format.svg?style=flat-square)](https://img.shields.io/npm/v/@superset-ui/number-format.svg?style=flat-square) | | [@superset-ui/translation](https://github.com/apache-superset/superset-ui/tree/master/packages/superset-ui-translation) | [![Version](https://img.shields.io/npm/v/@superset-ui/translation.svg?style=flat-square)](https://img.shields.io/npm/v/@superset-ui/translation.svg?style=flat-square) | #### Coming :soon: @@ -22,7 +24,6 @@ applications that leverage a Superset backend :chart_with_upwards_trend: - Data providers - Embeddable charts - Chart collections -- Demo storybook package ### Development diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/README.md b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/README.md new file mode 100644 index 000000000000..70fbe074f100 --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/README.md @@ -0,0 +1,57 @@ +## @superset-ui/number-format + +[![Version](https://img.shields.io/npm/v/@superset-ui/number-format.svg?style=flat)](https://img.shields.io/npm/v/@superset-ui/number-format.svg?style=flat) +[![David (path)](https://img.shields.io/david/apache-superset/superset-ui.svg?path=packages%2Fsuperset-ui-number-format&style=flat-square)](https://david-dm.org/apache-superset/superset-ui?path=packages/superset-ui-number-format) + +Description + +#### Example usage + +Functions `getNumberFormatter` and `formatNumber` should be used instead of calling `d3.format` directly. + +```js +import { getNumberFormatter } from '@superset-ui/number-format'; +const formatter = getNumberFormatter('.2f'); +console.log(formatter(1000)); +``` + +or + +```js +import { formatNumber } from '@superset-ui/number-format'; +console.log(formatNumber('.2f', 1000)); +``` + +It is powered by a registry to support registration of custom formatting, with fallback to `d3.format` and handle error for invalid format string. + +```js +import { getNumberFormatterRegistry, formatNumber, NumberFormatter } from '@superset-ui/number-format'; + +getNumberFormatterRegistry().registerValue('my_format', new NumberFormatter({ + id: 'my_format', + formatFunc: v => `my special format of ${v}` +}); + +console.log(formatNumber('my_format', 1000)); +// prints 'my special format of 1000' +``` + +It also define constants for common d3 formats. See the full list of formats in [NumberFormats.js](https://github.com/apache-superset/superset-ui/blob/master/packages/superset-ui-number-format/src/NumberFormats.js). + +```js +import { NumberFormats } from '@superset-ui-number-format'; + +NumberFormats.PERCENT // ,.2% +NumberFormats.PERCENT_3_POINT // ,.3% +``` + +#### API + +`fn(args)` + +- Do something + +### Development + +`@data-ui/build-config` is used to manage the build configuration for this package including babel +builds, jest testing, eslint, and prettier. diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/package.json b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/package.json new file mode 100644 index 000000000000..fbe051b6e7fb --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/package.json @@ -0,0 +1,33 @@ +{ + "name": "@superset-ui/number-format", + "version": "0.0.0", + "description": "Superset UI number format", + "sideEffects": false, + "main": "lib/index.js", + "module": "esm/index.js", + "files": [ + "esm", + "lib" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/apache-superset/superset-ui.git" + }, + "keywords": [ + "superset" + ], + "author": "Superset", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/apache-superset/superset-ui/issues" + }, + "homepage": "https://github.com/apache-superset/superset-ui#readme", + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@superset-ui/core": "^0.6.0", + "d3-format": "^1.3.2", + "lodash": "^4.17.11" + } +} diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/NumberFormats.js b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/NumberFormats.js new file mode 100644 index 000000000000..40ff71b62f99 --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/NumberFormats.js @@ -0,0 +1,31 @@ +export const DOLLAR = '$,.2f'; +export const DOLLAR_CHANGE = '+$,.2f'; +export const DOLLAR_ROUND = '$,d'; +export const DOLLAR_ROUND_CHANGE = '+$,d'; + +export const FLOAT_1_POINT = ',.1f'; +export const FLOAT_2_POINT = ',.2f'; +export const FLOAT_3_POINT = ',.3f'; +export const FLOAT = FLOAT_2_POINT; + +export const FLOAT_CHANGE_1_POINT = '+,.1f'; +export const FLOAT_CHANGE_2_POINT = '+,.2f'; +export const FLOAT_CHANGE_3_POINT = '+,.3f'; +export const FLOAT_CHANGE = FLOAT_CHANGE_2_POINT; + +export const INTEGER = ',d'; +export const INTEGER_CHANGE = '+,d'; + +export const PERCENT_1_POINT = ',.1%'; +export const PERCENT_2_POINT = ',.2%'; +export const PERCENT_3_POINT = ',.3%'; +export const PERCENT = PERCENT_2_POINT; + +export const PERCENT_CHANGE_1_POINT = '+,.1%'; +export const PERCENT_CHANGE_2_POINT = '+,.2%'; +export const PERCENT_CHANGE_3_POINT = '+,.3%'; +export const PERCENT_CHANGE = PERCENT_CHANGE_2_POINT; + +export const SI_1_DIGIT = '.1s'; +export const SI_2_DIGIT = '.2s'; +export const SI_3_DIGIT = '.3s'; diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/NumberFormatter.js b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/NumberFormatter.js new file mode 100644 index 000000000000..47b54b110834 --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/NumberFormatter.js @@ -0,0 +1,35 @@ +import { ExtensibleFunction, isRequired } from '@superset-ui/core'; + +export const PREVIEW_VALUE = 12345.432; + +export default class NumberFormatter extends ExtensibleFunction { + constructor({ + id = isRequired('config.id'), + label, + description = '', + formatFunc = isRequired('config.formatFunc'), + } = {}) { + super((...args) => this.format(...args)); + + this.id = id; + this.label = label || id; + this.description = description; + this.formatFunc = formatFunc; + } + + format(value) { + if (value === null || value === undefined || Number.isNaN(value)) { + return value; + } else if (value === Number.POSITIVE_INFINITY) { + return '∞'; + } else if (value === Number.NEGATIVE_INFINITY) { + return '-∞'; + } + + return this.formatFunc(value); + } + + preview(value = PREVIEW_VALUE) { + return `${value} => ${this.format(value)}`; + } +} diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/NumberFormatterRegistry.js b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/NumberFormatterRegistry.js new file mode 100644 index 000000000000..c0242f2fb973 --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/NumberFormatterRegistry.js @@ -0,0 +1,32 @@ +import { RegistryWithDefaultKey } from '@superset-ui/core'; +import D3Formatter from './formatters/D3Formatter'; +import { SI_3_DIGIT } from './NumberFormats'; + +const DEFAULT_FORMAT = SI_3_DIGIT; + +export default class NumberFormatterRegistry extends RegistryWithDefaultKey { + constructor() { + super({ + initialDefaultKey: DEFAULT_FORMAT, + name: 'NumberFormatter', + }); + } + + get(formatterId) { + const targetFormat = formatterId || this.defaultKey; + + if (this.has(targetFormat)) { + return super.get(targetFormat); + } + + // Create new formatter if does not exist + const formatter = new D3Formatter(targetFormat); + this.registerValue(targetFormat, formatter); + + return formatter; + } + + format(formatterId, value) { + return this.get(formatterId)(value); + } +} diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/NumberFormatterRegistrySingleton.js b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/NumberFormatterRegistrySingleton.js new file mode 100644 index 000000000000..2034ba08bbd8 --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/NumberFormatterRegistrySingleton.js @@ -0,0 +1,14 @@ +import { makeSingleton } from '@superset-ui/core'; +import NumberFormatterRegistry from './NumberFormatterRegistry'; + +const getInstance = makeSingleton(NumberFormatterRegistry); + +export default getInstance; + +export function getNumberFormatter(format) { + return getInstance().get(format); +} + +export function formatNumber(format, value) { + return getInstance().format(format, value); +} diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/formatters/D3Formatter.js b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/formatters/D3Formatter.js new file mode 100644 index 000000000000..2b6b3851d2d8 --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/formatters/D3Formatter.js @@ -0,0 +1,40 @@ +import isString from 'lodash/isString'; +import { format as d3Format } from 'd3-format'; +import { isRequired } from '@superset-ui/core'; +import NumberFormatter from '../NumberFormatter'; + +export default class D3Formatter extends NumberFormatter { + /** + * Pass only the D3 format string to constructor + * + * new D3Formatter('.2f'); + * + * or accompany it with human-readable label and description + * + * new D3Formatter({ + * id: '.2f', + * label: 'Float with 2 decimal points', + * description: 'lorem ipsum dolor sit amet', + * }); + * + * @param {String|Object} configOrFormatString + */ + constructor(configOrFormatString = isRequired('configOrFormatString')) { + const config = isString(configOrFormatString) + ? { id: configOrFormatString } + : configOrFormatString; + + let formatFunc; + let isInvalid = false; + + try { + formatFunc = d3Format(config.id); + } catch (e) { + formatFunc = () => `Invalid format: ${config.id}`; + isInvalid = true; + } + + super({ ...config, formatFunc }); + this.isInvalid = isInvalid; + } +} diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/formatters/SiAtMostNDigitFormatter.js b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/formatters/SiAtMostNDigitFormatter.js new file mode 100644 index 000000000000..9eca35732ded --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/formatters/SiAtMostNDigitFormatter.js @@ -0,0 +1,19 @@ +import { format as d3Format } from 'd3-format'; +import NumberFormatter from '../NumberFormatter'; + +export default class SiAtMostNDigitFormatter extends NumberFormatter { + constructor(n = 3) { + const siFormatter = d3Format(`.${n}s`); + + super({ + formatFunc: value => { + const si = siFormatter(value); + + // Removing trailing `.00` if any + return si.slice(-1) < 'A' ? parseFloat(si).toString() : si; + }, + id: `si_at_most_${n}_digit`, + label: `SI with at most ${n} significant digits`, + }); + } +} diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/index.js b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/index.js new file mode 100644 index 000000000000..4220fb1449f2 --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/src/index.js @@ -0,0 +1,10 @@ +import * as NumberFormats from './NumberFormats'; + +export { + default as getNumberFormatterRegistry, + formatNumber, + getNumberFormatter, +} from './NumberFormatterRegistrySingleton'; + +export { default as NumberFormatter, PREVIEW_VALUE } from './NumberFormatter'; +export { NumberFormats }; diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/NumberFormatter.test.js b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/NumberFormatter.test.js new file mode 100644 index 000000000000..dffb50329691 --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/NumberFormatter.test.js @@ -0,0 +1,64 @@ +import NumberFormatter from '../src/NumberFormatter'; + +describe('NumberFormatter', () => { + describe('new NumberFormatter(config)', () => { + it('requires config.id', () => { + expect(() => new NumberFormatter()).toThrow(); + }); + it('requires config.formatFunc', () => { + expect( + () => + new NumberFormatter({ + id: 'my_format', + }), + ).toThrow(); + }); + }); + describe('formatter is also a format function itself', () => { + const formatter = new NumberFormatter({ + id: 'fixed_3', + formatFunc: value => value.toFixed(3), + }); + it('returns formatted value', () => { + expect(formatter(12345.67)).toEqual('12345.670'); + }); + it('formatter(value) is the same with formatter.format(value)', () => { + const value = 12345.67; + expect(formatter(value)).toEqual(formatter.format(value)); + }); + }); + describe('.format(value)', () => { + const formatter = new NumberFormatter({ + id: 'fixed_3', + formatFunc: value => value.toFixed(3), + }); + it('handles null', () => { + expect(formatter.format(null)).toBeNull(); + }); + it('handles undefined', () => { + expect(formatter.format(undefined)).toBeUndefined(); + }); + it('handles NaN', () => { + expect(formatter.format(NaN)).toBeNaN(); + }); + it('handles positive and negative infinity', () => { + expect(formatter.format(Number.POSITIVE_INFINITY)).toEqual('∞'); + expect(formatter.format(Number.NEGATIVE_INFINITY)).toEqual('-∞'); + }); + it('otherwise returns formatted value', () => { + expect(formatter.format(12345.67)).toEqual('12345.670'); + }); + }); + describe('.preview(value)', () => { + const formatter = new NumberFormatter({ + id: 'fixed_2', + formatFunc: value => value.toFixed(2), + }); + it('returns string comparing value before and after formatting', () => { + expect(formatter.preview(100)).toEqual('100 => 100.00'); + }); + it('uses the default preview value if not specified', () => { + expect(formatter.preview()).toEqual('12345.432 => 12345.43'); + }); + }); +}); diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/NumberFormatterRegistry.test.js b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/NumberFormatterRegistry.test.js new file mode 100644 index 000000000000..0c006fe1f99d --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/NumberFormatterRegistry.test.js @@ -0,0 +1,32 @@ +import NumberFormatterRegistry from '../src/NumberFormatterRegistry'; +import NumberFormatter from '../src/NumberFormatter'; + +describe('NumberFormatterRegistry', () => { + let registry; + beforeEach(() => { + registry = new NumberFormatterRegistry(); + }); + describe('.get(format)', () => { + it('creates and returns a new formatter if does not exist', () => { + const formatter = registry.get('.2f'); + expect(formatter).toBeInstanceOf(NumberFormatter); + expect(formatter.format(100)).toEqual('100.00'); + }); + it('returns an existing formatter if already exists', () => { + const formatter = registry.get('.2f'); + const formatter2 = registry.get('.2f'); + expect(formatter).toBe(formatter2); + }); + it('falls back to default format if format is not specified', () => { + registry.setDefaultKey('.1f'); + const formatter = registry.get(); + expect(formatter.format(100)).toEqual('100.0'); + }); + }); + describe('.format(format, value)', () => { + it('return the value with the specified format', () => { + expect(registry.format('.2f', 100)).toEqual('100.00'); + expect(registry.format(',d', 100)).toEqual('100'); + }); + }); +}); diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/NumberFormatterRegistrySingleton.test.js b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/NumberFormatterRegistrySingleton.test.js new file mode 100644 index 000000000000..194b23778918 --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/NumberFormatterRegistrySingleton.test.js @@ -0,0 +1,29 @@ +import getNumberFormatterRegistry, { + getNumberFormatter, + formatNumber, +} from '../src/NumberFormatterRegistrySingleton'; +import NumberFormatterRegistry from '../src/NumberFormatterRegistry'; + +describe('NumberFormatterRegistrySingleton', () => { + describe('getNumberFormatterRegistry()', () => { + it('returns a NumberFormatterRegisry', () => { + expect(getNumberFormatterRegistry()).toBeInstanceOf(NumberFormatterRegistry); + }); + }); + describe('getNumberFormatter(format)', () => { + it('returns a format function', () => { + const format = getNumberFormatter('.3s'); + expect(format(12345)).toEqual('12.3k'); + }); + it('returns a format function even given invalid format', () => { + const format = getNumberFormatter('xkcd'); + expect(format(12345)).toEqual('Invalid format: xkcd'); + }); + }); + describe('formatNumber(format, value)', () => { + it('format the given number using the specified format', () => { + const output = formatNumber('.3s', 12345); + expect(output).toEqual('12.3k'); + }); + }); +}); diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/formatters/D3Formatter.test.js b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/formatters/D3Formatter.test.js new file mode 100644 index 000000000000..d6d064ab146e --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/formatters/D3Formatter.test.js @@ -0,0 +1,28 @@ +import D3Formatter from '../../src/formatters/D3Formatter'; + +describe('D3Formatter', () => { + describe('new D3Formatter(config)', () => { + it('requires configOrFormatString', () => { + expect(() => new D3Formatter()).toThrow(); + }); + describe('if configOrFormatString is string', () => { + it('uses the input as d3.format string', () => { + const formatter = new D3Formatter('.2f'); + expect(formatter.format(100)).toEqual('100.00'); + }); + }); + describe('if configOrFormatString is not string', () => { + it('requires field config.id', () => { + expect(() => new D3Formatter({})).toThrow(); + }); + it('uses d3.format(config.id) as format function', () => { + const formatter = new D3Formatter({ id: ',.4f' }); + expect(formatter.format(12345.67)).toEqual('12,345.6700'); + }); + it('if it is an invalid d3 format, the format function displays error message', () => { + const formatter = new D3Formatter({ id: 'i-am-groot' }); + expect(formatter.format(12345.67)).toEqual('Invalid format: i-am-groot'); + }); + }); + }); +}); diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/formatters/SiAtMostNDigitFormatter.test.js b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/formatters/SiAtMostNDigitFormatter.test.js new file mode 100644 index 000000000000..cfa19e289f75 --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/formatters/SiAtMostNDigitFormatter.test.js @@ -0,0 +1,51 @@ +import NumberFormatter from '../../src/NumberFormatter'; +import SiAtMostNDigitFormatter from '../../src/formatters/SiAtMostNDigitFormatter'; + +describe('SiAtMostNDigitFormatter', () => { + describe('new SiAtMostNDigitFormatter(n)', () => { + it('creates an instance of NumberFormatter', () => { + const formatter = new SiAtMostNDigitFormatter(3); + expect(formatter).toBeInstanceOf(NumberFormatter); + }); + it('when n is specified, it formats number in SI format with at most n significant digits', () => { + const formatter = new SiAtMostNDigitFormatter(2); + expect(formatter(10)).toBe('10'); + expect(formatter(1)).toBe('1'); + expect(formatter(1.0)).toBe('1'); + expect(formatter(10.0)).toBe('10'); + expect(formatter(10001)).toBe('10k'); + expect(formatter(10100)).toBe('10k'); + expect(formatter(111000000)).toBe('110M'); + expect(formatter(0.23)).toBe('230m'); + expect(formatter(0)).toBe('0'); + expect(formatter(-10)).toBe('-10'); + expect(formatter(-1)).toBe('-1'); + expect(formatter(-1.0)).toBe('-1'); + expect(formatter(-10.0)).toBe('-10'); + expect(formatter(-10001)).toBe('-10k'); + expect(formatter(-10101)).toBe('-10k'); + expect(formatter(-111000000)).toBe('-110M'); + expect(formatter(-0.23)).toBe('-230m'); + }); + it('when n is not specified, it defaults to n=3', () => { + const formatter = new SiAtMostNDigitFormatter(3); + expect(formatter(10)).toBe('10'); + expect(formatter(1)).toBe('1'); + expect(formatter(1.0)).toBe('1'); + expect(formatter(10.0)).toBe('10'); + expect(formatter(10001)).toBe('10.0k'); + expect(formatter(10100)).toBe('10.1k'); + expect(formatter(111000000)).toBe('111M'); + expect(formatter(0.23)).toBe('230m'); + expect(formatter(0)).toBe('0'); + expect(formatter(-10)).toBe('-10'); + expect(formatter(-1)).toBe('-1'); + expect(formatter(-1.0)).toBe('-1'); + expect(formatter(-10.0)).toBe('-10'); + expect(formatter(-10001)).toBe('-10.0k'); + expect(formatter(-10101)).toBe('-10.1k'); + expect(formatter(-111000000)).toBe('-111M'); + expect(formatter(-0.23)).toBe('-230m'); + }); + }); +}); diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/index.test.js b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/index.test.js new file mode 100644 index 000000000000..eaaa9ba3410c --- /dev/null +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-number-format/test/index.test.js @@ -0,0 +1,21 @@ +import { + formatNumber, + NumberFormats, + getNumberFormatter, + getNumberFormatterRegistry, + NumberFormatter, + PREVIEW_VALUE, +} from '../src/index'; + +describe('index', () => { + it('exports modules', () => { + [ + formatNumber, + NumberFormats, + getNumberFormatter, + getNumberFormatterRegistry, + NumberFormatter, + PREVIEW_VALUE, + ].forEach(x => expect(x).toBeDefined()); + }); +});