Skip to content

Commit 82db02f

Browse files
Merge pull request #2647 from contentstack/fix/dx-7521-progress-complete-count
DX-7521 | Fix invalid complete count in import progress UI
2 parents d19dd25 + b7476d0 commit 82db02f

2 files changed

Lines changed: 78 additions & 4 deletions

File tree

packages/contentstack-utilities/src/progress-summary/cli-progress-manager.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -421,14 +421,19 @@ export default class CLIProgressManager {
421421

422422
if (!this.showConsoleLogs && process.progressBar) {
423423
const totalProcessed = process.current;
424-
const percentage = Math.round((totalProcessed / process.total) * 100);
424+
// Reconcile the bar's total with the number of items actually processed so the
425+
// rendered "value/total" matches the "Complete (success/processed)" summary. A
426+
// process registered with an estimated total larger than the items actually ticked
427+
// would otherwise render mismatched counts, e.g. "37/37 | Complete (27/27)".
428+
process.progressBar.setTotal(totalProcessed);
429+
const percentage = totalProcessed > 0 ? 100 : 0;
425430
const formattedPercentage = this.formatPercentage(percentage);
426431
const statusText = success
427-
? getChalk().green(`✓ Complete (${process.successCount}/${process.current})`)
428-
: getChalk().red(`✗ Failed (${process.successCount}/${process.current})`);
432+
? getChalk().green(`✓ Complete (${process.successCount}/${totalProcessed})`)
433+
: getChalk().red(`✗ Failed (${process.successCount}/${totalProcessed})`);
429434
const displayName = this.formatProcessName(processName);
430435
const indentedLabel = ` ├─ ${displayName}`.padEnd(25);
431-
process.progressBar.update(process.total, {
436+
process.progressBar.update(totalProcessed, {
432437
label: success ? getChalk().green(indentedLabel) : getChalk().red(indentedLabel),
433438
status: statusText,
434439
percentage: formattedPercentage,

packages/contentstack-utilities/test/unit/cliProgressManager.test.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const mockProgressBar = {
3434
stop: sinon.stub(),
3535
increment: sinon.stub(),
3636
update: sinon.stub(),
37+
setTotal: sinon.stub(),
3738
};
3839

3940
const mockMultiBar = {
@@ -335,6 +336,74 @@ describe('CLIProgressManager', () => {
335336
});
336337
});
337338

339+
describe('Complete count reconciliation', () => {
340+
let bar: { update: sinon.SinonStub; setTotal: sinon.SinonStub; increment: sinon.SinonStub };
341+
342+
// Inject a stub bar at the rendering seam so assertions do not depend on the
343+
// load-order-sensitive cli-progress module mock (which does not bind in CI).
344+
function injectBar(processName: string) {
345+
bar = { update: sinon.stub(), setTotal: sinon.stub(), increment: sinon.stub() };
346+
(progressManager as any).processes.get(processName).progressBar = bar;
347+
}
348+
349+
beforeEach(() => {
350+
progressManager = new CLIProgressManager({
351+
enableNestedProgress: true,
352+
moduleName: 'RECONCILE_TEST',
353+
showConsoleLogs: false,
354+
});
355+
});
356+
357+
fancy.it('renders the processed count, not the registered estimate, when fewer items were ticked', () => {
358+
progressManager.addProcess('gf-update', 37);
359+
injectBar('gf-update');
360+
for (let i = 0; i < 27; i++) {
361+
progressManager.tick(true, `item-${i}`, null, 'gf-update');
362+
}
363+
364+
progressManager.completeProcess('gf-update', true);
365+
366+
expect(bar.setTotal.calledWith(27)).to.equal(true);
367+
expect(bar.update.lastCall.args[0]).to.equal(27);
368+
});
369+
370+
fancy.it('renders the full count unchanged when every registered item was ticked', () => {
371+
progressManager.addProcess('entries-create', 59);
372+
injectBar('entries-create');
373+
for (let i = 0; i < 59; i++) {
374+
progressManager.tick(true, `item-${i}`, null, 'entries-create');
375+
}
376+
377+
progressManager.completeProcess('entries-create', true);
378+
379+
expect(bar.update.lastCall.args[0]).to.equal(59);
380+
});
381+
382+
fancy.it('renders the registered total when a process completes with no ticks (skip case)', () => {
383+
progressManager.addProcess('skipped', 5);
384+
injectBar('skipped');
385+
386+
progressManager.completeProcess('skipped', true);
387+
388+
expect(bar.update.lastCall.args[0]).to.equal(5);
389+
});
390+
391+
fancy.it('reconciles the denominator for a failed process with partial ticks', () => {
392+
progressManager.addProcess('entries', 59);
393+
injectBar('entries');
394+
for (let i = 0; i < 38; i++) {
395+
progressManager.tick(true, `ok-${i}`, null, 'entries');
396+
}
397+
for (let i = 0; i < 3; i++) {
398+
progressManager.tick(false, `err-${i}`, 'boom', 'entries');
399+
}
400+
401+
progressManager.completeProcess('entries', false);
402+
403+
expect(bar.update.lastCall.args[0]).to.equal(41);
404+
});
405+
});
406+
338407
describe('Progress Tracking', () => {
339408
beforeEach(() => {
340409
progressManager = new CLIProgressManager({

0 commit comments

Comments
 (0)