Skip to content

Commit

Permalink
Merge pull request #805 from chromaui/tom/ap-3561-cli-add-new-ontaskp…
Browse files Browse the repository at this point in the history
…rogress-event-triggered-by-upload-and

Add a `onTaskProgress` option and report progress on it
  • Loading branch information
tmeasday committed Aug 31, 2023
2 parents 2cfc8d4 + c4d4c8b commit 7a525aa
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 3 deletions.
46 changes: 45 additions & 1 deletion node-src/tasks/snapshot.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { takeSnapshots } from './snapshot';

const env = { CHROMATIC_POLL_INTERVAL: 0 };
const env = { CHROMATIC_POLL_INTERVAL: 0, CHROMATIC_OUTPUT_INTERVAL: 0 };
const log = { error: jest.fn(), info: jest.fn() };
const matchesBranch = () => false;

Expand Down Expand Up @@ -106,4 +106,48 @@ describe('takeSnapshots', () => {
expect(ctx.build).toEqual({ ...build, changeCount: 2, status: 'FAILED', completedAt: 1 });
expect(ctx.exitCode).toBe(3);
});

it('calls onTaskProgress with progress', async () => {
const client = { runQuery: jest.fn(), setAuthorization: jest.fn() };
const build = {
app: { repository: { provider: 'github' } },
number: 1,
features: {},
reportToken: 'report-token',
actualTestCount: 5,
inProgressCount: 5,
};
const ctx = {
client,
env,
git: { matchesBranch },
log,
options: { onTaskProgress: jest.fn() },
build,
} as any;

client.runQuery.mockReturnValueOnce({
app: { build: { status: 'IN_PROGRESS', inProgressCount: 5 } },
});
client.runQuery.mockReturnValueOnce({
app: { build: { status: 'IN_PROGRESS', inProgressCount: 3 } },
});
client.runQuery.mockReturnValueOnce({
app: { build: { changeCount: 0, status: 'PASSED', completedAt: 1, inProgressCount: 0 } },
});

await takeSnapshots(ctx, {} as any);

expect(ctx.options.onTaskProgress).toHaveBeenCalledTimes(2);
expect(ctx.options.onTaskProgress).toHaveBeenCalledWith(expect.any(Object), {
progress: 1,
total: 5,
unit: 'snapshots',
});
expect(ctx.options.onTaskProgress).toHaveBeenCalledWith(expect.any(Object), {
progress: 3,
total: 5,
unit: 'snapshots',
});
});
});
4 changes: 4 additions & 0 deletions node-src/tasks/snapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ export const takeSnapshots = async (ctx: Context, task: Task) => {
const updateProgress = throttle(
({ cursor, label }) => {
task.output = pending(ctx, { cursor, label }).output;
ctx.options.onTaskProgress?.(
{ ...ctx },
{ progress: cursor, total: actualTestCount, unit: 'snapshots' }
);
},
// Avoid spamming the logs with progress updates in non-interactive mode
ctx.options.interactive ? ctx.env.CHROMATIC_POLL_INTERVAL : ctx.env.CHROMATIC_OUTPUT_INTERVAL
Expand Down
82 changes: 81 additions & 1 deletion node-src/tasks/upload.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const readFileSync = <jest.MockedFunction<typeof fs.readFileSync>>fs.readFileSyn
const statSync = <jest.MockedFunction<typeof fs.statSync>>fs.statSync;
const progress = <jest.MockedFunction<typeof progressStream>>progressStream;

const env = { CHROMATIC_RETRIES: 2 };
const env = { CHROMATIC_RETRIES: 2, CHROMATIC_OUTPUT_INTERVAL: 0 };
const log = { info: jest.fn(), warn: jest.fn(), debug: jest.fn() };
const http = { fetch: jest.fn() };

Expand Down Expand Up @@ -242,4 +242,84 @@ describe('uploadStorybook', () => {
expect(ctx.uploadedBytes).toBe(84);
expect(ctx.isolatorUrl).toBe('https://asdqwe.chromatic.com/iframe.html');
});

it('calls onTaskProgress with progress', async () => {
const client = { runQuery: jest.fn() };
client.runQuery.mockReturnValue({
getUploadUrls: {
domain: 'https://asdqwe.chromatic.com',
urls: [
{
path: 'iframe.html',
url: 'https://asdqwe.chromatic.com/iframe.html',
contentType: 'text/html',
},
{
path: 'index.html',
url: 'https://asdqwe.chromatic.com/index.html',
contentType: 'text/html',
},
],
},
});

createReadStream.mockReturnValue({ pipe: jest.fn((x) => x) } as any);
progress.mockImplementation((() => {
let progressCb;
return {
on: jest.fn((name, cb) => {
progressCb = cb;
}),
sendProgress: (delta: number) => progressCb({ delta }),
};
}) as any);
http.fetch.mockReset().mockImplementation(async (url, { body }) => {
// body is just the mocked progress stream, as pipe returns it
body.sendProgress(21);
body.sendProgress(21);
return { ok: true };
});

const fileInfo = {
lengths: [
{ knownAs: 'iframe.html', contentLength: 42 },
{ knownAs: 'index.html', contentLength: 42 },
],
paths: ['iframe.html', 'index.html'],
total: 84,
};
const ctx = {
client,
env,
log,
http,
sourceDir: '/static/',
options: { onTaskProgress: jest.fn() },
fileInfo,
announcedBuild: { id: '1' },
} as any;
await uploadStorybook(ctx, {} as any);

expect(ctx.options.onTaskProgress).toHaveBeenCalledTimes(4);
expect(ctx.options.onTaskProgress).toHaveBeenCalledWith(expect.any(Object), {
progress: 21,
total: 84,
unit: 'bytes',
});
expect(ctx.options.onTaskProgress).toHaveBeenCalledWith(expect.any(Object), {
progress: 42,
total: 84,
unit: 'bytes',
});
expect(ctx.options.onTaskProgress).toHaveBeenCalledWith(expect.any(Object), {
progress: 63,
total: 84,
unit: 'bytes',
});
expect(ctx.options.onTaskProgress).toHaveBeenCalledWith(expect.any(Object), {
progress: 84,
total: 84,
unit: 'bytes',
});
});
});
2 changes: 2 additions & 0 deletions node-src/tasks/upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,8 @@ export const uploadStorybook = async (ctx: Context, task: Task) => {
(progress, total) => {
const percentage = Math.round((progress / total) * 100);
task.output = uploading({ percentage }).output;

ctx.options.onTaskProgress?.({ ...ctx }, { progress, total, unit: 'bytes' });
},
// Avoid spamming the logs with progress updates in non-interactive mode
ctx.options.interactive ? 100 : ctx.env.CHROMATIC_OUTPUT_INTERVAL
Expand Down
6 changes: 6 additions & 0 deletions node-src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ export interface Options {

/** A callback that is called at the completion of each task */
onTaskComplete?: (ctx: Context) => void;

/** A callback that is called during tasks that have incremental progress */
onTaskProgress?: (
ctx: Context,
status: { progress: number; total: number; unit: string }
) => void;
}

export interface Context {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "chromatic",
"version": "6.24.1",
"version": "6.25.0-canary.0",
"description": "Automate visual testing across browsers. Gather UI feedback. Versioned documentation.",
"keywords": [
"storybook-addon",
Expand Down

0 comments on commit 7a525aa

Please sign in to comment.