Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ This is the log of notable changes to EAS CLI and related packages.

- [eas-cli] Refresh README as an EAS product landing page. ([#3844](https://github.com/expo/eas-cli/pull/3844) by [@szdziedzic](https://github.com/szdziedzic))
- [eas-cli] Fix the EAS logo not rendering in the repository root README. ([#4093](https://github.com/expo/eas-cli/pull/4093) by [@szdziedzic](https://github.com/szdziedzic))
- [eas-cli] Improve wording for usage printouts. ([#4094](https://github.com/expo/eas-cli/pull/4094) by [@kadikraman](https://github.com/kadikraman))

## [21.3.0](https://github.com/expo/eas-cli/releases/tag/v21.3.0) - 2026-07-27

Expand Down
45 changes: 45 additions & 0 deletions packages/eas-cli/src/commands/account/__tests__/usage.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient';
import { extractUsageData } from '../../../commandUtils/usageUtils';
import {
AccountFullUsageQuery as AccountFullUsageQueryType,
EasService,
EasServiceMetric,
UsageMetricType,
} from '../../../graphql/generated';
import { AccountQuery } from '../../../graphql/queries/AccountQuery';
import Log from '../../../log';
import { calculatePercentUsed, createProgressBar } from '../../../utils/usage/checkForOverages';
import { displayUsage } from '../usage';

jest.mock('../../../graphql/queries/AccountQuery');
jest.mock('../../../log', () => ({
__esModule: true,
...jest.requireActual('../../../log'),
default: {
log: jest.fn(),
newLine: jest.fn(),
},
link: jest.fn((url: string, opts?: { text?: string }) => opts?.text ?? url),
}));

function createMockFullUsageData(
overrides: Partial<{
Expand Down Expand Up @@ -206,6 +218,39 @@ describe('AccountQuery', () => {
});
});

describe('displayUsage', () => {
const mockLog = jest.mocked(Log.log);

beforeEach(() => {
mockLog.mockClear();
});

it('labels usage beyond included credits as "additional usage"', () => {
const usageData = createMockFullUsageData({
buildValue: 55,
buildLimit: 50,
mauValue: 3500,
mauLimit: 3000,
buildOverageCost: 1500,
updateOverageCost: 250,
});
const displayData = extractUsageData(usageData);

displayUsage(displayData, usageData);

// eslint-disable-next-line no-control-regex
const output = mockLog.mock.calls
.flat()
.join('\n')
.replace(/\u001b\[\d+m/g, '');
expect(output).toContain('Unique Updaters (additional usage): 500 users ($2.50)');
expect(output).toContain('Additional usage: $17.50');
expect(output).toContain('Builds: $15.00');
expect(output).toContain('Updates: $2.50');
expect(output.toLowerCase()).not.toContain('overage');
});
});

describe('calculatePercentUsed', () => {
it('calculates correct percentage', () => {
expect(calculatePercentUsed(50, 100)).toBe(50);
Expand Down
12 changes: 6 additions & 6 deletions packages/eas-cli/src/commands/account/usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function displayBandwidthMetric(metric: UsageMetricDisplay, indent: string = '

if (metric.overageValue > 0) {
Log.log(
`${indent}${metric.name} (overage): ${chalk.red(
`${indent}${metric.name} (additional usage): ${chalk.red(
formatBytesDisplay(metric.overageValue)
)} (${formatCurrency(metric.overageCost)})`
);
Expand All @@ -84,7 +84,7 @@ function displayMetric(metric: UsageMetricDisplay, indent: string = ' '): void

if (metric.overageValue > 0) {
Log.log(
`${indent}${metric.name} (overage): ${chalk.red(
`${indent}${metric.name} (additional usage): ${chalk.red(
`${formatNumber(metric.overageValue)} ${metric.unit ?? ''}`
)} (${formatCurrency(metric.overageCost)})`
);
Expand All @@ -95,7 +95,7 @@ function billingUrl(accountName: string): string {
return `https://expo.dev/accounts/${accountName}/settings/billing`;
}

function displayUsage(data: UsageDisplayData, usageData: AccountFullUsageData): void {
export function displayUsage(data: UsageDisplayData, usageData: AccountFullUsageData): void {
const subscription = usageData.subscription;

Log.newLine();
Expand Down Expand Up @@ -172,9 +172,9 @@ function displayUsage(data: UsageDisplayData, usageData: AccountFullUsageData):
}

if (data.totalOverageCostCents > 0) {
Log.log(` Current overages: ${chalk.yellow(formatCurrency(data.totalOverageCostCents))}`);
Log.log(` Additional usage: ${chalk.yellow(formatCurrency(data.totalOverageCostCents))}`);
if (data.builds.overageCostCents > 0) {
Log.log(` Build overages: ${formatCurrency(data.builds.overageCostCents)}`);
Log.log(` Builds: ${formatCurrency(data.builds.overageCostCents)}`);
// Show breakdown by worker size
for (const overage of data.builds.overagesByWorkerSize) {
const platformName = overage.platform === AppPlatform.Ios ? 'iOS' : 'Android';
Expand All @@ -188,7 +188,7 @@ function displayUsage(data: UsageDisplayData, usageData: AccountFullUsageData):
}
}
if (data.updates.overageCostCents > 0) {
Log.log(` Update overages: ${formatCurrency(data.updates.overageCostCents)}`);
Log.log(` Updates: ${formatCurrency(data.updates.overageCostCents)}`);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ describe('maybeWarnAboutUsageOveragesAsync', () => {

expect(mockWarn).toHaveBeenCalledWith(
expect.stringContaining(
"You've used 10 builds beyond your included credits this billing period ($15.00 in overages so far)."
"You've used 10 builds beyond your included credits this billing period ($15.00 in additional usage so far)."
)
);
expect(mockWarn).toHaveBeenCalledWith(
Expand Down Expand Up @@ -289,7 +289,7 @@ describe('maybeWarnAboutUsageOveragesAsync', () => {

expect(mockWarn).toHaveBeenCalledWith(
expect.stringContaining(
"You've used 3 builds beyond your included credits this billing period ($4.50 in overages so far)."
"You've used 3 builds beyond your included credits this billing period ($4.50 in additional usage so far)."
)
);
});
Expand Down Expand Up @@ -558,7 +558,7 @@ describe('displayOverageWarning', () => {

expect(mockWarn).toHaveBeenCalledWith(
expect.stringContaining(
"You've used 10 builds beyond your included credits this billing period ($15.00 in overages so far)."
"You've used 10 builds beyond your included credits this billing period ($15.00 in additional usage so far)."
)
);
expect(mockWarn).toHaveBeenCalledWith(
Expand All @@ -579,7 +579,7 @@ describe('displayOverageWarning', () => {

expect(mockWarn).toHaveBeenCalledWith(
expect.stringContaining(
"You've used 1 build beyond your included credits this billing period ($1.50 in overages so far)."
"You've used 1 build beyond your included credits this billing period ($1.50 in additional usage so far)."
)
);
});
Expand Down
2 changes: 1 addition & 1 deletion packages/eas-cli/src/utils/usage/checkForOverages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ export function displayOverageWarning({
// tier === 'over' && paid plan
Log.warn(
chalk.bold(
`You've used ${overageCount} build${overageCount === 1 ? '' : 's'} beyond your included credits this billing period (${formatCents(overageCostCents)} in overages so far).`
`You've used ${overageCount} build${overageCount === 1 ? '' : 's'} beyond your included credits this billing period (${formatCents(overageCostCents)} in additional usage so far).`
)
);
Log.warn(
Expand Down
Loading