Skip to content

Commit

Permalink
feat(screenshot): create directories for screenshot file
Browse files Browse the repository at this point in the history
  • Loading branch information
JoelEinbinder authored Aug 17, 2020
1 parent 0e9793c commit dfa1f10
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 8 deletions.
5 changes: 4 additions & 1 deletion src/chromium/crProtocolHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { Protocol } from './protocol';
import * as fs from 'fs';
import * as util from 'util';
import * as types from '../types';
import { mkdirIfNeeded } from '../helper';

export function getExceptionMessage(exceptionDetails: Protocol.Runtime.ExceptionDetails): string {
if (exceptionDetails.exception)
Expand All @@ -42,8 +43,10 @@ export async function releaseObject(client: CRSession, objectId: string) {
export async function readProtocolStream(client: CRSession, handle: string, path: string | null): Promise<Buffer> {
let eof = false;
let fd: number | undefined;
if (path)
if (path) {
await mkdirIfNeeded(path);
fd = await util.promisify(fs.open)(path, 'w');
}
const bufs = [];
while (!eof) {
const response = await client.send('IO.read', {handle});
Expand Down
5 changes: 2 additions & 3 deletions src/download.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import * as util from 'util';
import { Page } from './page';
import { Events } from './events';
import { Readable } from 'stream';
import { assert } from './helper';
import { assert, mkdirIfNeeded } from './helper';

export class Download {
private _downloadsPath: string;
Expand Down Expand Up @@ -92,8 +92,7 @@ export class Download {

async _saveAs(downloadPath: string) {
const fileName = path.join(this._downloadsPath, this._uuid);
// This will harmlessly throw on windows if the dirname is the root directory.
await util.promisify(fs.mkdir)(path.dirname(downloadPath), {recursive: true}).catch(() => {});
await mkdirIfNeeded(downloadPath);
await util.promisify(fs.copyFile)(fileName, downloadPath);
}

Expand Down
8 changes: 8 additions & 0 deletions src/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ import * as fs from 'fs';
import * as os from 'os';
import * as removeFolder from 'rimraf';
import * as util from 'util';
import * as path from 'path';
import * as types from './types';
import { Progress } from './progress';
import * as debug from 'debug';

const removeFolderAsync = util.promisify(removeFolder);
const readFileAsync = util.promisify(fs.readFile.bind(fs));
const mkdirAsync = util.promisify(fs.mkdir.bind(fs));

export type RegisteredListener = {
emitter: EventEmitter;
Expand Down Expand Up @@ -353,6 +355,12 @@ export function getFromENV(name: string) {
return value;
}


export async function mkdirIfNeeded(filePath: string) {
// This will harmlessly throw on windows if the dirname is the root directory.
await mkdirAsync(path.dirname(filePath), {recursive: true}).catch(() => {});
}

const escapeGlobChars = new Set(['/', '$', '^', '+', '.', '(', ')', '=', '!', '|']);

export const helper = Helper;
Expand Down
6 changes: 4 additions & 2 deletions src/rpc/client/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*/

import { Events } from './events';
import { assert, helper, Listener } from '../../helper';
import { assert, helper, Listener, mkdirIfNeeded } from '../../helper';
import { TimeoutSettings } from '../../timeoutSettings';
import { BindingCallChannel, BindingCallInitializer, PageChannel, PageInitializer, PagePdfParams, FrameWaitForSelectorOptions, FrameDispatchEventOptions, FrameSetContentOptions, FrameGotoOptions, PageReloadOptions, PageGoBackOptions, PageGoForwardOptions, PageScreenshotOptions, FrameClickOptions, FrameDblclickOptions, FrameFillOptions, FrameFocusOptions, FrameTextContentOptions, FrameInnerTextOptions, FrameInnerHTMLOptions, FrameGetAttributeOptions, FrameHoverOptions, FrameSetInputFilesOptions, FrameTypeOptions, FramePressOptions, FrameCheckOptions, FrameUncheckOptions } from '../channels';
import { parseError, serializeError } from '../serializers';
Expand Down Expand Up @@ -425,8 +425,10 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
async screenshot(options: PageScreenshotOptions & { path?: string } = {}): Promise<Buffer> {
return this._wrapApiCall('page.screenshot', async () => {
const buffer = Buffer.from((await this._channel.screenshot(options)).binary, 'base64');
if (options.path)
if (options.path) {
await mkdirIfNeeded(options.path);
await fsWriteFileAsync(options.path, buffer);
}
return buffer;
});
}
Expand Down
6 changes: 4 additions & 2 deletions src/screenshotter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import * as fs from 'fs';
import * as mime from 'mime';
import * as util from 'util';
import * as dom from './dom';
import { assert, helper } from './helper';
import { assert, helper, mkdirIfNeeded } from './helper';
import { Page } from './page';
import * as types from './types';
import { rewriteErrorMessage } from './utils/stackTrace';
Expand Down Expand Up @@ -153,8 +153,10 @@ export class Screenshotter {
if (shouldSetDefaultBackground)
await this._page._delegate.setBackgroundColor();
progress.throwIfAborted(); // Avoid side effects.
if (options.path)
if (options.path) {
await mkdirIfNeeded(options.path);
await util.promisify(fs.writeFile)(options.path, buffer);
}
if ((options as any).__testHookAfterScreenshot)
await (options as any).__testHookAfterScreenshot();
return buffer;
Expand Down
8 changes: 8 additions & 0 deletions test/chromium/tracing.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ it.skip(!CHROMIUM)('should output a trace', async({browser, page, server, output
expect(fs.existsSync(outputFile)).toBe(true);
});

it.skip(!CHROMIUM)('should create directories as needed', async({browser, page, server, tmpDir}) => {
const filePath = path.join(tmpDir, 'these', 'are', 'directories');
await (browser as ChromiumBrowser).startTracing(page, {screenshots: true, path: filePath});
await page.goto(server.PREFIX + '/grid.html');
await (browser as ChromiumBrowser).stopTracing();
expect(fs.existsSync(filePath)).toBe(true);
});

it.skip(!CHROMIUM)('should run with custom categories if provided', async({browser, page, outputFile}) => {
await (browser as ChromiumBrowser).startTracing(page, {path: outputFile, categories: ['disabled-by-default-v8.cpu_profiler.hires']});
await (browser as ChromiumBrowser).stopTracing();
Expand Down
19 changes: 19 additions & 0 deletions test/page-screenshot.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
*/
import './base.fixture';
import utils from './utils';
import path from 'path';
import fs from 'fs';

const { HEADLESS } = testOptions;

// Firefox headful produces a different image.
Expand Down Expand Up @@ -246,3 +249,19 @@ it.skip(ffheadful)('should work with iframe in shadow', async({page, server, gol
await page.goto(server.PREFIX + '/grid-iframe-in-shadow.html');
expect(await page.screenshot()).toMatchImage(golden('screenshot-iframe.png'));
});

it('path option should work', async({page, server, golden, tmpDir}) => {
await page.setViewportSize({width: 500, height: 500});
await page.goto(server.PREFIX + '/grid.html');
const outputPath = path.join(tmpDir, 'screenshot.png');
await page.screenshot({path: outputPath});
expect(await fs.promises.readFile(outputPath)).toMatchImage(golden('screenshot-sanity.png'));
});

it('path option should create subdirectories', async({page, server, golden, tmpDir}) => {
await page.setViewportSize({width: 500, height: 500});
await page.goto(server.PREFIX + '/grid.html');
const outputPath = path.join(tmpDir, 'these', 'are', 'directories', 'screenshot.png');
await page.screenshot({path: outputPath});
expect(await fs.promises.readFile(outputPath)).toMatchImage(golden('screenshot-sanity.png'));
});

0 comments on commit dfa1f10

Please sign in to comment.