diff --git a/src/lib/components/billing/couponInput.svelte b/src/lib/components/billing/couponInput.svelte
index 482f216f89..369619afed 100644
--- a/src/lib/components/billing/couponInput.svelte
+++ b/src/lib/components/billing/couponInput.svelte
@@ -1,5 +1,6 @@
@@ -14,7 +15,7 @@
- {#if $$slots.actions}
+ {#if $$slots.actions && !hideFooter}
diff --git a/src/lib/constants.ts b/src/lib/constants.ts
index 393623360b..e20bbfc07f 100644
--- a/src/lib/constants.ts
+++ b/src/lib/constants.ts
@@ -279,345 +279,6 @@ export const eventServices: Array = [
}
];
-export const usageRates = {
- 'tier-0': [
- {
- id: 'members',
- resource: 'Organization members',
- amount: 1,
- unit: '',
- rate: '$20/member'
- },
- { id: 'bandwith', resource: 'Bandwidth', amount: 10, unit: 'GB', rate: '$0.04/GB' },
- { id: 'storage', resource: 'Storage', amount: 2, unit: 'GB', rate: '$0.025/GB' },
- {
- id: 'executions',
- resource: 'Function executions',
- amount: 750000,
- unit: 'executions',
- rate: '$2/1M executions'
- },
- {
- id: 'users',
- resource: 'Active users',
- amount: 200000,
- unit: 'AU',
- rate: '$0.0012/user'
- },
- {
- id: 'connections',
- resource: 'Concurrent connections',
- amount: 750,
- unit: 'connections',
- rate: '$5/1K connections'
- }
- ],
- 'tier-1': [
- {
- id: 'members',
- resource: 'Organization members',
- amount: 'Unlimited',
- unit: '',
- rate: '$20/member'
- },
- { id: 'bandwith', resource: 'Bandwidth', amount: 1, unit: 'TB', rate: '$0.04/GB' },
- { id: 'storage', resource: 'Storage', amount: 150, unit: 'GB', rate: '$0.025/GB' },
- {
- id: 'executions',
- resource: 'Function executions',
- amount: 3500000,
- unit: 'executions',
- rate: '$2/1M executions'
- },
- {
- id: 'users',
- resource: 'Active users',
- amount: 200000,
- unit: 'AU',
- rate: '$0.0012/user'
- },
- {
- id: 'connections',
- resource: 'Concurrent connections',
- amount: 750,
- unit: 'connections',
- rate: '$5/1K connections'
- }
- ],
- 'tier-2': [
- {
- id: 'members',
- resource: 'Organization members',
- amount: 'Unlimited',
- unit: '',
- rate: '$20/member'
- },
- { id: 'bandwith', resource: 'Bandwidth', amount: 1, unit: 'TB', rate: '$0.04/GB' },
- { id: 'storage', resource: 'Storage', amount: 150, unit: 'GB', rate: '$0.025/GB' },
- {
- id: 'executions',
- resource: 'Function executions',
- amount: 3500000,
- unit: 'executions',
- rate: '$2/1M executions'
- },
- {
- id: 'users',
- resource: 'Active users',
- amount: 200000,
- unit: 'AU',
- rate: '$0.0012/user'
- },
- {
- id: 'connections',
- resource: 'Concurrent connections',
- amount: 750,
- unit: 'connections',
- rate: '$5/1K connections'
- }
- ]
-};
-
-//resources: bandwidth, buckets, file size limit, functions, executions, users,teams,logs, members, platforms, webhooks, databases, connections, messages
-export const limitRates = {
- 'tier-0': [
- {
- id: 'bandwith',
- amount: 10,
- unit: 'GB'
- },
- {
- id: 'buckets',
- amount: 3,
- unit: ''
- },
- {
- id: 'file-size-limit',
- amount: 1,
- unit: 'MB'
- },
- {
- id: 'storage',
- amount: 5,
- unit: 'GB'
- },
- {
- id: 'functions',
- amount: 1,
- unit: ''
- },
- {
- id: 'executions',
- amount: 750000,
- unit: 'executions'
- },
- {
- id: 'users',
- amount: 200000,
- unit: 'AU'
- },
-
- {
- id: 'teams',
- amount: 1,
- unit: ''
- },
-
- {
- id: 'logs',
- amount: 1,
- unit: ''
- },
-
- {
- id: 'members',
- amount: 1,
- unit: ''
- },
- {
- id: 'platforms',
- amount: 1,
- unit: ''
- },
- {
- id: 'webhooks',
- amount: 1,
- unit: ''
- },
- {
- id: 'databases',
- amount: 1,
- unit: ''
- },
- {
- id: 'connections',
- amount: 1,
- unit: ''
- },
- {
- id: 'messages',
- amount: 1,
- unit: ''
- }
- ],
- 'tier-1': [
- {
- id: 'bandwith',
- amount: 10,
- unit: 'GB'
- },
- {
- id: 'buckets',
- amount: 1,
- unit: ''
- },
- {
- id: 'file-size-limit',
- amount: 5,
- unit: 'MB'
- },
- {
- id: 'storage',
- amount: 5,
- unit: 'GB'
- },
- {
- id: 'functions',
- amount: 1,
- unit: ''
- },
- {
- id: 'executions',
- amount: 750000,
- unit: 'executions'
- },
- {
- id: 'users',
- amount: 200000,
- unit: 'AU'
- },
-
- {
- id: 'teams',
- amount: 1,
- unit: ''
- },
- {
- id: 'logs',
- amount: 1,
- unit: ''
- },
- {
- id: 'members',
- amount: 1,
- unit: ''
- },
- {
- id: 'platforms',
- amount: 1,
- unit: ''
- },
- {
- id: 'webhooks',
- amount: 1,
- unit: ''
- },
- {
- id: 'databases',
- amount: 1,
- unit: ''
- },
- {
- id: 'connections',
- amount: 1,
- unit: ''
- },
- {
- id: 'messages',
- amount: 1,
- unit: ''
- }
- ],
- 'tier-2': [
- {
- id: 'bandwith',
- amount: 10,
- unit: 'GB'
- },
- {
- id: 'buckets',
- amount: 1,
- unit: ''
- },
- {
- id: 'file-size-limit',
- amount: 5,
- unit: 'MB'
- },
- {
- id: 'storage',
- amount: 5,
- unit: 'GB'
- },
- {
- id: 'functions',
- amount: 1,
- unit: ''
- },
- {
- id: 'executions',
- amount: 750000,
- unit: 'executions'
- },
- {
- id: 'users',
- amount: 200000,
- unit: 'AU'
- },
-
- {
- id: 'teams',
- amount: 1,
- unit: ''
- },
- {
- id: 'logs',
- amount: 1,
- unit: ''
- },
- {
- id: 'members',
- amount: 1,
- unit: ''
- },
- {
- id: 'platforms',
- amount: 1,
- unit: ''
- },
- {
- id: 'webhooks',
- amount: 1,
- unit: ''
- },
- {
- id: 'databases',
- amount: 1,
- unit: ''
- },
- {
- id: 'connections',
- amount: 1,
- unit: ''
- },
- {
- id: 'messages',
- amount: 1,
- unit: ''
- }
- ]
-};
-
export enum BillingPlan {
STARTER = 'tier-0',
PRO = 'tier-1',
diff --git a/src/lib/helpers/numbers.ts b/src/lib/helpers/numbers.ts
index 796160cc2e..f9a0fdba63 100644
--- a/src/lib/helpers/numbers.ts
+++ b/src/lib/helpers/numbers.ts
@@ -20,3 +20,12 @@ export function formatNumberWithCommas(number: number): string {
const formatter = new Intl.NumberFormat('en');
return formatter.format(number);
}
+
+export function formatCurrency(number: number, locale = 'en-US', currency = 'USD'): string {
+ if (isNaN(number)) return String(number);
+ const formatter = new Intl.NumberFormat(locale, {
+ style: 'currency',
+ currency
+ });
+ return formatter.format(number);
+}
diff --git a/src/routes/console/onboarding/+page.svelte b/src/routes/console/onboarding/+page.svelte
index 8785fb04e8..39d318db97 100644
--- a/src/routes/console/onboarding/+page.svelte
+++ b/src/routes/console/onboarding/+page.svelte
@@ -18,6 +18,7 @@
import CreateOrganizationCloud from '../createOrganizationCloud.svelte';
import { tierToPlan, type Tier } from '$lib/stores/billing';
import { createOrganization } from '../wizard/cloudOrganization/store';
+ import { formatCurrency } from '$lib/helpers/numbers';
let name: string;
let id: string;
@@ -25,8 +26,8 @@
let plan: Tier;
const options = [
- { value: BillingPlan.STARTER, label: 'Starter - $0/month' },
- { value: BillingPlan.PRO, label: 'Pro - $15/month + add-ons' }
+ { value: BillingPlan.STARTER, label: `Starter - ${formatCurrency(0)}/month` },
+ { value: BillingPlan.PRO, label: `Pro - ${formatCurrency(0)}/month + add-ons` }
];
onMount(() => {
diff --git a/src/routes/console/organization-[organization]/billing/availableCredit.svelte b/src/routes/console/organization-[organization]/billing/availableCredit.svelte
index dcaf3f3535..a2eed718bc 100644
--- a/src/routes/console/organization-[organization]/billing/availableCredit.svelte
+++ b/src/routes/console/organization-[organization]/billing/availableCredit.svelte
@@ -18,6 +18,7 @@
import AddCreditWizard from './addCreditWizard.svelte';
import { Button } from '$lib/elements/forms';
import AddCreditModal from './addCreditModal.svelte';
+ import { formatCurrency } from '$lib/helpers/numbers';
import { BillingPlan } from '$lib/constants';
import ChangeOrganizationTierCloud from '$routes/console/changeOrganizationTierCloud.svelte';
import { trackEvent } from '$lib/actions/analytics';
@@ -68,7 +69,7 @@
}
-
+
Available credit
Appwrite credit will automatically be applied to your next invoice.
@@ -88,7 +89,7 @@
Credit balance
- ${balance}
+ {formatCurrency(balance)}
{#if creditList?.total}
@@ -114,7 +115,7 @@
{toLocaleDate(credit.expiration)}
- ${credit.credits}
+ {formatCurrency(credit.credits)}
{/each}
diff --git a/src/routes/console/organization-[organization]/billing/paymentHistory.svelte b/src/routes/console/organization-[organization]/billing/paymentHistory.svelte
index a0894992b6..edf381c3f4 100644
--- a/src/routes/console/organization-[organization]/billing/paymentHistory.svelte
+++ b/src/routes/console/organization-[organization]/billing/paymentHistory.svelte
@@ -21,6 +21,7 @@
TableScroll
} from '$lib/elements/table';
import { toLocaleDate } from '$lib/helpers/date';
+ import { formatCurrency } from '$lib/helpers/numbers';
import type { Invoice, InvoiceList } from '$lib/sdk/billing';
import { sdk } from '$lib/stores/sdk';
import { VARS } from '$lib/system';
@@ -92,7 +93,9 @@
{status === 'requires_authentication' ? 'failed' : status}
- ${invoice.amount}
+
+ {formatCurrency(invoice.amount)}
+
Total to-date:
{/if}
- ${isTrial ? 0 : currentPlan?.price}
+ {isTrial ? formatCurrency(0) : formatCurrency(currentPlan?.price)}
@@ -78,7 +78,7 @@
{extraMembers.value}
{extraMembers.name}
- ${extraMembers.amount}
+ {formatCurrency(extraMembers.amount)}
@@ -98,7 +98,7 @@
{excess.name}
- ${excess.amount}
+ {formatCurrency(excess.amount)}
{/if}
{#if ['users', 'executions'].includes(excess.name)}
@@ -108,13 +108,15 @@
>{abbreviateNumber(excess.value)}
{excess.name}
- ${excess.amount}
+ {formatCurrency(excess.amount)}
{/if}
{/each}
Total to-date:
- ${currentInvoice?.amount}
+
+ {formatCurrency(currentInvoice?.amount ?? 0)}
+
diff --git a/src/routes/console/organization-[organization]/createMember.svelte b/src/routes/console/organization-[organization]/createMember.svelte
index 5bd7742ba2..338d08a3b5 100644
--- a/src/routes/console/organization-[organization]/createMember.svelte
+++ b/src/routes/console/organization-[organization]/createMember.svelte
@@ -11,6 +11,7 @@
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
import { isCloud } from '$lib/system';
import { plansInfo } from '$lib/stores/billing';
+ import { formatCurrency } from '$lib/helpers/numbers';
export let showCreate = false;
@@ -63,7 +64,7 @@
You can add unlimited organization members on the {plan.name} plan at no cost.
{:else if $organization?.billingPlan === BillingPlan.PRO}
You can add unlimited organization members on the {plan.name} plan for
- ${plan.addons.member.price} each per billing period .
+ {formatCurrency(plan.addons.member.price)} each per billing period .
{/if}
{/if}
diff --git a/src/routes/console/wizard/cloudOrganization/confirmDetails.svelte b/src/routes/console/wizard/cloudOrganization/confirmDetails.svelte
index 63194d59e9..a7c6209f6d 100644
--- a/src/routes/console/wizard/cloudOrganization/confirmDetails.svelte
+++ b/src/routes/console/wizard/cloudOrganization/confirmDetails.svelte
@@ -4,6 +4,7 @@
import { BillingPlan } from '$lib/constants';
import { Pill } from '$lib/elements';
import { toLocaleDate } from '$lib/helpers/date';
+ import { formatCurrency } from '$lib/helpers/numbers';
import { WizardStep } from '$lib/layout';
import type { Coupon } from '$lib/sdk/billing';
import { plansInfo } from '$lib/stores/billing';
@@ -92,28 +93,30 @@
on:validation={(e) => ($createOrganization.couponCode = e.detail.code)} />
{plan.name} plan
- ${plan.price}
+ {formatCurrency(plan.price)}
Additional members ({collaboratorsNumber})
- ${collaboratorPrice * collaboratorsNumber}
+ {formatCurrency(collaboratorPrice * collaboratorsNumber)}
{#if couponData?.status === 'active'}
Credits applied ({couponData.credits})
- -${couponData.credits}
+ -{formatCurrency(couponData.credits)}
{/if}
{/if}
+ {@const estimatedTotal =
+ couponData?.status === 'active'
+ ? totalExpences - couponData.credits >= 0
+ ? totalExpences - couponData.credits
+ : 0
+ : totalExpences}
Estimated total
- ${couponData?.status === 'active'
- ? totalExpences - couponData.credits >= 0
- ? totalExpences - couponData.credits
- : 0
- : totalExpences}
+ {formatCurrency(estimatedTotal)}
diff --git a/src/routes/console/wizard/cloudOrganization/inviteMembers.svelte b/src/routes/console/wizard/cloudOrganization/inviteMembers.svelte
index 3c84e8c819..e1359f39b7 100644
--- a/src/routes/console/wizard/cloudOrganization/inviteMembers.svelte
+++ b/src/routes/console/wizard/cloudOrganization/inviteMembers.svelte
@@ -11,6 +11,7 @@
TableHeader,
TableRow
} from '$lib/elements/table';
+ import { formatCurrency } from '$lib/helpers/numbers';
import { WizardStep } from '$lib/layout';
import { plansInfo } from '$lib/stores/billing';
import { createOrganization } from './store';
@@ -47,8 +48,8 @@
added will receive an email invite to your organization on completion.
{:else if $createOrganization.billingPlan === BillingPlan.PRO}
You can add unlimited organization members on the {plan.name} plan for
- ${plan.addons.member.price} each per month . Each member added will receive an
- email invite to your organization on completion.
+ {formatCurrency(plan.addons.member.price)} each per month . Each member added will
+ receive an email invite to your organization on completion.
{/if}
@@ -81,7 +82,7 @@
{collaborator}
{#if $createOrganization.billingPlan === BillingPlan.PRO}
- 15$
+ {formatCurrency(15)}
{/if}
- {tierFree.name} - ${freePlan?.price}/month
+ {tierFree.name} - {formatCurrency(freePlan?.price ?? 0)}/month
{tierFree.description}
@@ -100,8 +101,8 @@
- {tierPro.name} - ${proPlan.price}/month per organization member + exta
- usage
+ {tierPro.name} - {formatCurrency(proPlan?.price ?? 0)}/month per
+ organization member + exta usage
{tierPro.description}
@@ -122,7 +123,8 @@
class="u-flex u-flex-vertical u-gap-4 u-width-full-line"
class:u-opacity-50={disabled}>
- {tierScale.name} - ${scalePlan.price}/month + extra usage
+ {tierScale.name} - {formatCurrency(scalePlan?.price ?? 0)}/month + extra
+ usage
{tierScale.description}
diff --git a/src/routes/console/wizard/cloudOrganization/usageRates.svelte b/src/routes/console/wizard/cloudOrganization/usageRates.svelte
index e90faac661..ac8fb21c58 100644
--- a/src/routes/console/wizard/cloudOrganization/usageRates.svelte
+++ b/src/routes/console/wizard/cloudOrganization/usageRates.svelte
@@ -13,7 +13,7 @@
import { organization } from '$lib/stores/organization';
import { createOrganization } from './store';
import { plansInfo, type Tier } from '$lib/stores/billing';
- import { abbreviateNumber } from '$lib/helpers/numbers';
+ import { abbreviateNumber, formatCurrency } from '$lib/helpers/numbers';
import { BillingPlan } from '$lib/constants';
export let show = false;
@@ -87,7 +87,7 @@
{#if !isFree}
- ${plan.addons.member.price}/{usage?.unit}
+ {formatCurrency(plan.addons.member.price)}/{usage?.unit}
{/if}
@@ -100,7 +100,9 @@
{#if !isFree}
- ${addon?.price}/{['MB', 'GB', 'TB'].includes(addon?.unit)
+ {formatCurrency(addon?.price)}/{['MB', 'GB', 'TB'].includes(
+ addon?.unit
+ )
? addon?.value
: abbreviateNumber(addon?.value, 0)}{usage?.unit}
diff --git a/src/routes/console/wizard/cloudOrganizationChangeTier/choosePlan.svelte b/src/routes/console/wizard/cloudOrganizationChangeTier/choosePlan.svelte
index 76ff8498ef..5a94e9ec8d 100644
--- a/src/routes/console/wizard/cloudOrganizationChangeTier/choosePlan.svelte
+++ b/src/routes/console/wizard/cloudOrganizationChangeTier/choosePlan.svelte
@@ -12,6 +12,7 @@
import { sizeToBytes } from '$lib/helpers/sizeConvertion';
import { Pill } from '$lib/elements';
import { BillingPlan } from '$lib/constants';
+ import { formatCurrency } from '$lib/helpers/numbers';
let usage: OrganizationUsage = null;
let members: Models.MembershipList = null;
@@ -127,7 +128,7 @@
class="u-flex u-flex-vertical u-gap-4 u-width-full-line"
class:u-opacity-50={disabled}>
- {tierFree.name} - ${freePlan.price}/month
+ {tierFree.name} - {formatCurrency(freePlan.price)}/month
{tierFree.description}
@@ -150,8 +151,8 @@
class="u-flex u-flex-vertical u-gap-4 u-width-full-line"
class:u-opacity-50={disabled}>
- {tierPro.name} - ${proPlan.price}/month per organization member + extra
- usage
+ {tierPro.name} - {formatCurrency(proPlan.price)}/month per organization
+ member + extra usage
{tierPro.description}
@@ -178,7 +179,7 @@
class="u-flex u-flex-vertical u-gap-4 u-width-full-line"
class:u-opacity-50={disabled}>
- {tierScale.name} - ${scalePlan.price}/month + extra usage
+ {tierScale.name} - {formatCurrency(scalePlan.price)}/month + extra usage
{tierScale.description}
diff --git a/src/routes/console/wizard/cloudOrganizationChangeTier/confirmDetails.svelte b/src/routes/console/wizard/cloudOrganizationChangeTier/confirmDetails.svelte
index 7191ee3774..e62c6af3fb 100644
--- a/src/routes/console/wizard/cloudOrganizationChangeTier/confirmDetails.svelte
+++ b/src/routes/console/wizard/cloudOrganizationChangeTier/confirmDetails.svelte
@@ -4,6 +4,7 @@
import { BillingPlan } from '$lib/constants';
import { FormList, InputTextarea } from '$lib/elements/forms';
import { toLocaleDate } from '$lib/helpers/date';
+ import { formatCurrency } from '$lib/helpers/numbers';
import { WizardStep } from '$lib/layout';
import type { Coupon } from '$lib/sdk/billing';
import { plansInfo } from '$lib/stores/billing';
@@ -104,28 +105,30 @@
on:validation={(e) => ($changeOrganizationTier.couponCode = e.detail.code)} />
{plan.name} plan
- ${plan.price}
+ {formatCurrency(plan.price)}
Additional members ({collaboratorsNumber})
- ${collaboratorPrice * collaboratorsNumber}
+ {formatCurrency(collaboratorPrice * collaboratorsNumber)}
{#if couponData?.status === 'active'}
Credits applied ({couponData.credits})
- -${couponData.credits}
+ -{formatCurrency(couponData.credits)}
{/if}
{/if}
+ {@const estimatedTotal =
+ couponData?.status === 'active'
+ ? totalExpences - couponData.credits >= 0
+ ? totalExpences - couponData.credits
+ : 0
+ : totalExpences}
Estimated total
- ${couponData?.status === 'active'
- ? totalExpences - couponData.credits >= 0
- ? totalExpences - couponData.credits
- : 0
- : totalExpences}
+ {formatCurrency(estimatedTotal)}
diff --git a/src/routes/console/wizard/cloudOrganizationChangeTier/inviteMembers.svelte b/src/routes/console/wizard/cloudOrganizationChangeTier/inviteMembers.svelte
index 32e30c8b38..94d86e2671 100644
--- a/src/routes/console/wizard/cloudOrganizationChangeTier/inviteMembers.svelte
+++ b/src/routes/console/wizard/cloudOrganizationChangeTier/inviteMembers.svelte
@@ -18,6 +18,7 @@
import { user } from '$lib/stores/user';
import { organization } from '$lib/stores/organization';
import { BillingPlan } from '$lib/constants';
+ import { formatCurrency } from '$lib/helpers/numbers';
const plan = $plansInfo.get($changeOrganizationTier.billingPlan);
@@ -63,8 +64,8 @@
added will receive an email invite to your organization on completion.
{:else if $changeOrganizationTier.billingPlan === BillingPlan.PRO}
You can add unlimited organization members on the {plan.name} plan for
- ${plan.addons.member.price} each per month . Each member added will receive an
- email invite to your organization on completion.
+ {formatCurrency(plan.addons.member.price)} each per month . Each member added will
+ receive an email invite to your organization on completion.
{/if}
@@ -97,7 +98,7 @@
{collaborator}
{#if $changeOrganizationTier.billingPlan === BillingPlan.PRO}
- 15$
+ {formatCurrency(15)}
{/if}
diff --git a/tests/unit/helpers/numbers.test.ts b/tests/unit/helpers/numbers.test.ts
new file mode 100644
index 0000000000..5b1dfe3b09
--- /dev/null
+++ b/tests/unit/helpers/numbers.test.ts
@@ -0,0 +1,85 @@
+import '@testing-library/jest-dom';
+import {
+ abbreviateNumber,
+ formatCurrency,
+ formatNumberWithCommas,
+ toDecimals
+} from '$lib/helpers/numbers';
+
+/*
+Abbreviate Number
+*/
+test('return the same number as a string if it is less than 1000', () => {
+ expect(abbreviateNumber(500)).toEqual('500');
+});
+
+test('abbreviate thousands correctly', () => {
+ expect(abbreviateNumber(1500)).toEqual('1.5K');
+ expect(abbreviateNumber(2000)).toEqual('2K');
+});
+
+test('abbreviate millions correctly', () => {
+ expect(abbreviateNumber(1500000)).toEqual('1.5M');
+ expect(abbreviateNumber(2000000)).toEqual('2M');
+});
+
+test('handle NaN correctly', () => {
+ expect(abbreviateNumber(NaN)).toEqual('NaN');
+});
+
+test('handle decimals correctly', () => {
+ expect(abbreviateNumber(1500, 2)).toEqual('1.50K');
+ expect(abbreviateNumber(1500000, 2)).toEqual('1.50M');
+});
+
+/*
+To Decimals
+*/
+test('correctly format numbers with default decimal', () => {
+ expect(toDecimals(1.2345)).toEqual(1.2);
+});
+
+test('correctly format numbers with specified decimals', () => {
+ expect(toDecimals(1.2345, 3)).toEqual(1.234);
+});
+
+test('correctly format integers', () => {
+ expect(toDecimals(5)).toEqual(5.0);
+});
+
+test('correctly handle zero', () => {
+ expect(toDecimals(0)).toEqual(0.0);
+});
+
+/*
+Format Number with Commas
+*/
+test('format numbers with commas correctly', () => {
+ expect(formatNumberWithCommas(1000)).toBe('1,000');
+ expect(formatNumberWithCommas(1000000)).toBe('1,000,000');
+ expect(formatNumberWithCommas(1234567890)).toBe('1,234,567,890');
+});
+
+test('return the input as a string if it is not a number', () => {
+ expect(formatNumberWithCommas(NaN)).toEqual('NaN');
+});
+
+/*
+Format Currency
+*/
+test('format number to USD by default', () => {
+ expect(formatCurrency(1000)).toEqual('$1,000.00');
+});
+
+test('format number to specified currency', () => {
+ expect(formatCurrency(1000, 'en-US', 'EUR')).toEqual('€1,000.00');
+});
+
+//The formatCurrency function is using a non-breaking space before the currency symbol, so regular spaces break the test. Hence the \u00A0. XD
+test('format number according to specified locale and currency', () => {
+ expect(formatCurrency(1000, 'de-DE', 'EUR')).toEqual('1.000,00\u00A0€');
+});
+
+test('return the input as a string if it is not a number', () => {
+ expect(formatCurrency(NaN)).toEqual('NaN');
+});