screenci 0.0.69 → 0.0.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -122
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +12 -4
- package/dist/cli.js.map +1 -1
- package/dist/docs/manifest.d.ts +54 -23
- package/dist/docs/manifest.d.ts.map +1 -1
- package/dist/docs/manifest.js +18 -7
- package/dist/docs/manifest.js.map +1 -1
- package/dist/docs/video-sources/cli.screenci.d.ts +2 -0
- package/dist/docs/video-sources/cli.screenci.d.ts.map +1 -0
- package/dist/docs/video-sources/{cli.video.js → cli.screenci.js} +1 -1
- package/dist/docs/video-sources/cli.screenci.js.map +1 -0
- package/dist/docs/video-sources/installation.screenci.d.ts +2 -0
- package/dist/docs/video-sources/installation.screenci.d.ts.map +1 -0
- package/dist/docs/video-sources/{installation.video.js → installation.screenci.js} +1 -1
- package/dist/docs/video-sources/installation.screenci.js.map +1 -0
- package/dist/docs/video-sources/landing.screenci.d.ts +2 -0
- package/dist/docs/video-sources/landing.screenci.d.ts.map +1 -0
- package/dist/docs/video-sources/{landing.video.js → landing.screenci.js} +1 -1
- package/dist/docs/video-sources/landing.screenci.js.map +1 -0
- package/dist/docs/video-sources/locator-highlight-animated.screenci.d.ts +2 -0
- package/dist/docs/video-sources/locator-highlight-animated.screenci.d.ts.map +1 -0
- package/dist/docs/video-sources/locator-highlight-animated.screenci.js +53 -0
- package/dist/docs/video-sources/locator-highlight-animated.screenci.js.map +1 -0
- package/dist/docs/video-sources/locator-highlight-still.screenci.d.ts +2 -0
- package/dist/docs/video-sources/locator-highlight-still.screenci.d.ts.map +1 -0
- package/dist/docs/video-sources/locator-highlight-still.screenci.js +24 -0
- package/dist/docs/video-sources/locator-highlight-still.screenci.js.map +1 -0
- package/dist/docs/video-sources/product-pitch.screenci.d.ts +2 -0
- package/dist/docs/video-sources/product-pitch.screenci.d.ts.map +1 -0
- package/dist/docs/video-sources/product-pitch.screenci.js +136 -0
- package/dist/docs/video-sources/product-pitch.screenci.js.map +1 -0
- package/dist/docs/video-sources/public-urls.screenci.d.ts +2 -0
- package/dist/docs/video-sources/public-urls.screenci.d.ts.map +1 -0
- package/dist/docs/video-sources/public-urls.screenci.js +34 -0
- package/dist/docs/video-sources/public-urls.screenci.js.map +1 -0
- package/dist/docs/video-sources/studio.screenci.d.ts +2 -0
- package/dist/docs/video-sources/studio.screenci.d.ts.map +1 -0
- package/dist/docs/video-sources/{studio.video.js → studio.screenci.js} +1 -1
- package/dist/docs/video-sources/studio.screenci.js.map +1 -0
- package/dist/docs/videos.d.ts +36 -15
- package/dist/docs/videos.d.ts.map +1 -1
- package/dist/docs/videos.js +27 -2
- package/dist/docs/videos.js.map +1 -1
- package/dist/e2e/screenshot.e2e.d.ts +2 -0
- package/dist/e2e/screenshot.e2e.d.ts.map +1 -0
- package/dist/e2e/screenshot.e2e.js +73 -0
- package/dist/e2e/screenshot.e2e.js.map +1 -0
- package/dist/index.d.ts +7 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/src/asset.d.ts +119 -15
- package/dist/src/asset.d.ts.map +1 -1
- package/dist/src/asset.js +310 -124
- package/dist/src/asset.js.map +1 -1
- package/dist/src/audio.d.ts +14 -0
- package/dist/src/audio.d.ts.map +1 -1
- package/dist/src/audio.js +4 -1
- package/dist/src/audio.js.map +1 -1
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +9 -3
- package/dist/src/config.js.map +1 -1
- package/dist/src/contextOptions.d.ts +48 -0
- package/dist/src/contextOptions.d.ts.map +1 -0
- package/dist/src/contextOptions.js +71 -0
- package/dist/src/contextOptions.js.map +1 -0
- package/dist/src/crop.d.ts +93 -0
- package/dist/src/crop.d.ts.map +1 -0
- package/dist/src/crop.js +133 -0
- package/dist/src/crop.js.map +1 -0
- package/dist/src/cue.d.ts +17 -4
- package/dist/src/cue.d.ts.map +1 -1
- package/dist/src/cue.js +31 -3
- package/dist/src/cue.js.map +1 -1
- package/dist/src/defaults.d.ts +6 -0
- package/dist/src/defaults.d.ts.map +1 -1
- package/dist/src/defaults.js +6 -0
- package/dist/src/defaults.js.map +1 -1
- package/dist/src/dimensions.d.ts +6 -0
- package/dist/src/dimensions.d.ts.map +1 -1
- package/dist/src/dimensions.js +15 -0
- package/dist/src/dimensions.js.map +1 -1
- package/dist/src/events.d.ts +152 -10
- package/dist/src/events.d.ts.map +1 -1
- package/dist/src/events.js +61 -3
- package/dist/src/events.js.map +1 -1
- package/dist/src/htmlRasterizer.d.ts +43 -0
- package/dist/src/htmlRasterizer.d.ts.map +1 -1
- package/dist/src/htmlRasterizer.js +32 -10
- package/dist/src/htmlRasterizer.js.map +1 -1
- package/dist/src/init.js +7 -7
- package/dist/src/init.js.map +1 -1
- package/dist/src/overlayFlush.d.ts +18 -0
- package/dist/src/overlayFlush.d.ts.map +1 -0
- package/dist/src/overlayFlush.js +56 -0
- package/dist/src/overlayFlush.js.map +1 -0
- package/dist/src/overlayRect.d.ts +69 -0
- package/dist/src/overlayRect.d.ts.map +1 -0
- package/dist/src/overlayRect.js +55 -0
- package/dist/src/overlayRect.js.map +1 -0
- package/dist/src/recording.d.ts +3 -2
- package/dist/src/recording.d.ts.map +1 -1
- package/dist/src/recordingData.d.ts +20 -0
- package/dist/src/recordingData.d.ts.map +1 -1
- package/dist/src/runtimeContext.d.ts +19 -1
- package/dist/src/runtimeContext.d.ts.map +1 -1
- package/dist/src/runtimeContext.js +15 -0
- package/dist/src/runtimeContext.js.map +1 -1
- package/dist/src/screenshot.d.ts +105 -0
- package/dist/src/screenshot.d.ts.map +1 -0
- package/dist/src/screenshot.js +188 -0
- package/dist/src/screenshot.js.map +1 -0
- package/dist/src/stillCapture.d.ts +68 -0
- package/dist/src/stillCapture.d.ts.map +1 -0
- package/dist/src/stillCapture.js +119 -0
- package/dist/src/stillCapture.js.map +1 -0
- package/dist/src/studio.d.ts +8 -11
- package/dist/src/studio.d.ts.map +1 -1
- package/dist/src/studio.js +2 -25
- package/dist/src/studio.js.map +1 -1
- package/dist/src/types.d.ts +100 -8
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js.map +1 -1
- package/dist/src/video.d.ts +20 -0
- package/dist/src/video.d.ts.map +1 -1
- package/dist/src/video.js +71 -24
- package/dist/src/video.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/skills/screenci/SKILL.md +10 -10
- package/skills/screenci/references/init.md +1 -1
- package/skills/screenci/references/record.md +2 -2
- package/dist/docs/video-sources/cli.video.d.ts +0 -2
- package/dist/docs/video-sources/cli.video.d.ts.map +0 -1
- package/dist/docs/video-sources/cli.video.js.map +0 -1
- package/dist/docs/video-sources/installation.video.d.ts +0 -2
- package/dist/docs/video-sources/installation.video.d.ts.map +0 -1
- package/dist/docs/video-sources/installation.video.js.map +0 -1
- package/dist/docs/video-sources/landing.video.d.ts +0 -2
- package/dist/docs/video-sources/landing.video.d.ts.map +0 -1
- package/dist/docs/video-sources/landing.video.js.map +0 -1
- package/dist/docs/video-sources/studio.video.d.ts +0 -2
- package/dist/docs/video-sources/studio.video.d.ts.map +0 -1
- package/dist/docs/video-sources/studio.video.js.map +0 -1
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { TestType, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, TestDetails, TestInfo } from '@playwright/test';
|
|
2
|
+
import type { RecordOptions, RenderOptions, ScreenCIPage } from './types.js';
|
|
3
|
+
import type { StudioRenderOptionsSentinel } from './studio.js';
|
|
4
|
+
import type { CropTarget, CropOptions } from './crop.js';
|
|
5
|
+
/**
|
|
6
|
+
* The `crop` fixture argument. Call it inside a `screenshot()` body to crop the
|
|
7
|
+
* implicit end-of-body capture to a locator or pixel region. Replaces the
|
|
8
|
+
* old module-level `crop()` function; the crop is recorded per test.
|
|
9
|
+
*/
|
|
10
|
+
export type CropFixture = (target: CropTarget, options?: CropOptions) => Promise<void>;
|
|
11
|
+
type ScreenshotFixtureOptions = {
|
|
12
|
+
recordOptions: RecordOptions;
|
|
13
|
+
renderOptions: RenderOptions | StudioRenderOptionsSentinel | undefined;
|
|
14
|
+
};
|
|
15
|
+
type ScreenshotFixtures = {
|
|
16
|
+
crop: CropFixture;
|
|
17
|
+
};
|
|
18
|
+
type ScreenshotType = TestType<PlaywrightTestArgs & PlaywrightTestOptions & ScreenshotFixtureOptions & ScreenshotFixtures & PlaywrightWorkerArgs & PlaywrightWorkerOptions, PlaywrightWorkerArgs & PlaywrightWorkerOptions>;
|
|
19
|
+
type ScreenshotArgs = Omit<PlaywrightTestArgs, 'page'> & {
|
|
20
|
+
page: ScreenCIPage;
|
|
21
|
+
} & PlaywrightTestOptions & ScreenshotFixtureOptions & ScreenshotFixtures & PlaywrightWorkerArgs & PlaywrightWorkerOptions;
|
|
22
|
+
type ScreenshotBody = (args: ScreenshotArgs, testInfo: TestInfo) => void | Promise<void>;
|
|
23
|
+
/** Conditional overloads shared by skip / fixme / fail */
|
|
24
|
+
type ConditionalOverloads = ((condition?: boolean, description?: string) => void) & ((condition?: boolean, callback?: () => string) => void);
|
|
25
|
+
interface ScreenshotCallSignatures {
|
|
26
|
+
/**
|
|
27
|
+
* Declares a ScreenCI screenshot test.
|
|
28
|
+
*
|
|
29
|
+
* Drives the page like a `video()` test, then captures the final state as a
|
|
30
|
+
* still image. The capture is framed on the configured background with the
|
|
31
|
+
* branded frame, cropped with the `crop` fixture argument, and decorated with
|
|
32
|
+
* overlays at render time. The viewport is derived from
|
|
33
|
+
* `recordOptions.aspectRatio` and `recordOptions.quality`;
|
|
34
|
+
* `recordOptions.deviceScaleFactor` raises the DPI.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* import { screenshot } from 'screenci'
|
|
39
|
+
*
|
|
40
|
+
* screenshot('Dashboard hero', async ({ page, crop }) => {
|
|
41
|
+
* await page.goto('https://app.example.com/dashboard')
|
|
42
|
+
* await crop(page.getByTestId('revenue-card'), { padding: 48 })
|
|
43
|
+
* })
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
(title: string, body: ScreenshotBody): void;
|
|
47
|
+
/**
|
|
48
|
+
* Declares a ScreenCI screenshot test with additional details (tags,
|
|
49
|
+
* annotations, etc.).
|
|
50
|
+
*/
|
|
51
|
+
(title: string, details: TestDetails, body: ScreenshotBody): void;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Recursive interface so `.only`, `.skip`, `.fixme`, `.fail`, and `.slow`
|
|
55
|
+
* surface `page: ScreenCIPage` instead of the raw Playwright `page: Page`.
|
|
56
|
+
*/
|
|
57
|
+
interface Screenshot extends ScreenshotCallSignatures {
|
|
58
|
+
only: Screenshot;
|
|
59
|
+
skip: Screenshot & ConditionalOverloads;
|
|
60
|
+
fixme: Screenshot & ConditionalOverloads;
|
|
61
|
+
fail: Screenshot & ConditionalOverloads;
|
|
62
|
+
slow: Screenshot & ((condition?: boolean, description?: string) => void);
|
|
63
|
+
beforeEach(inner: (args: ScreenshotArgs, testInfo: TestInfo) => Promise<void> | void): void;
|
|
64
|
+
beforeEach(title: string, inner: (args: ScreenshotArgs, testInfo: TestInfo) => Promise<void> | void): void;
|
|
65
|
+
afterEach(inner: (args: ScreenshotArgs, testInfo: TestInfo) => Promise<void> | void): void;
|
|
66
|
+
afterEach(title: string, inner: (args: ScreenshotArgs, testInfo: TestInfo) => Promise<void> | void): void;
|
|
67
|
+
describe: ScreenshotType['describe'];
|
|
68
|
+
beforeAll: ScreenshotType['beforeAll'];
|
|
69
|
+
afterAll: ScreenshotType['afterAll'];
|
|
70
|
+
use: ScreenshotType['use'];
|
|
71
|
+
extend: ScreenshotType['extend'];
|
|
72
|
+
step: ScreenshotType['step'];
|
|
73
|
+
info: ScreenshotType['info'];
|
|
74
|
+
expect: ScreenshotType['expect'];
|
|
75
|
+
setTimeout: ScreenshotType['setTimeout'];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* ScreenCI screenshot test fixture.
|
|
79
|
+
*
|
|
80
|
+
* Extended Playwright test that captures a branded still image of the final page
|
|
81
|
+
* state. Configure capture options with `screenshot.use()` or in your config.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```ts
|
|
85
|
+
* import { screenshot, createOverlays } from 'screenci'
|
|
86
|
+
*
|
|
87
|
+
* const overlays = createOverlays({
|
|
88
|
+
* badge: { path: '../assets/new-badge.png', x: 0.72, y: 0.06, width: 0.2 },
|
|
89
|
+
* })
|
|
90
|
+
*
|
|
91
|
+
* screenshot.use({
|
|
92
|
+
* colorScheme: 'dark',
|
|
93
|
+
* recordOptions: { quality: '1440p', deviceScaleFactor: 2 },
|
|
94
|
+
* })
|
|
95
|
+
*
|
|
96
|
+
* screenshot('Dashboard hero', async ({ page, crop }) => {
|
|
97
|
+
* await page.goto('https://app.example.com/dashboard')
|
|
98
|
+
* await overlays.badge()
|
|
99
|
+
* await crop(page.getByTestId('revenue-card'), { padding: 0.06 })
|
|
100
|
+
* })
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export declare const screenshot: Screenshot;
|
|
104
|
+
export {};
|
|
105
|
+
//# sourceMappingURL=screenshot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../../src/screenshot.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { test as base } from '@playwright/test';
|
|
2
|
+
import { mkdir, rm } from 'fs/promises';
|
|
3
|
+
import { join, relative } from 'path';
|
|
4
|
+
import { getDimensions } from './dimensions.js';
|
|
5
|
+
import { DEFAULT_VIDEO_OPTIONS, DEFAULT_ASPECT_RATIO, DEFAULT_QUALITY, DEFAULT_SCREENSHOT_DEVICE_SCALE_FACTOR, } from './defaults.js';
|
|
6
|
+
import { EventRecorder } from './events.js';
|
|
7
|
+
import { instrumentBrowser, instrumentContext } from './instrument.js';
|
|
8
|
+
import { getChromiumLaunchOptions } from './browserLaunchOptions.js';
|
|
9
|
+
import { createScreenCIRuntimeContext } from './runtimeContext.js';
|
|
10
|
+
import { escapeFileSystemPathSegment } from './fileSystemName.js';
|
|
11
|
+
import { buildScreenCIContextOptions, resolveDeviceScaleFactor, } from './contextOptions.js';
|
|
12
|
+
import { resolveCrop } from './crop.js';
|
|
13
|
+
import { getRuntimePage, setRuntimeCrop } from './runtimeContext.js';
|
|
14
|
+
import { ScreenciError } from './errors.js';
|
|
15
|
+
import { withActiveRecordingContext } from './video.js';
|
|
16
|
+
/** File name of the raw page capture written beside `data.json`. */
|
|
17
|
+
const SCREENSHOT_FILE_NAME = 'screenshot.png';
|
|
18
|
+
const _screenshotBase = base.extend({
|
|
19
|
+
recordOptions: [DEFAULT_VIDEO_OPTIONS, { option: true }],
|
|
20
|
+
renderOptions: [undefined, { option: true }],
|
|
21
|
+
crop: async ({}, use) => {
|
|
22
|
+
await use(async (target, options) => {
|
|
23
|
+
const page = getRuntimePage();
|
|
24
|
+
if (page === null) {
|
|
25
|
+
throw new ScreenciError('crop() requires an active ScreenCI page. Call it inside a screenshot() body.');
|
|
26
|
+
}
|
|
27
|
+
setRuntimeCrop(await resolveCrop(target, page, options));
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
browser: async ({ playwright }, use) => {
|
|
31
|
+
const shouldRecord = process.env.SCREENCI_RECORDING === 'true';
|
|
32
|
+
const launchOptions = getChromiumLaunchOptions(shouldRecord);
|
|
33
|
+
const browser = await playwright.chromium.launch(launchOptions);
|
|
34
|
+
instrumentBrowser(browser);
|
|
35
|
+
await use(browser);
|
|
36
|
+
if (browser.isConnected()) {
|
|
37
|
+
await browser.close();
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
context: async ({ browser, recordOptions, colorScheme, locale, timezoneId, userAgent, geolocation, permissions, extraHTTPHeaders, httpCredentials, ignoreHTTPSErrors, offline, storageState, baseURL, bypassCSP, acceptDownloads, javaScriptEnabled, hasTouch, isMobile, deviceScaleFactor, }, use) => {
|
|
41
|
+
const aspectRatio = recordOptions.aspectRatio ?? DEFAULT_ASPECT_RATIO;
|
|
42
|
+
const quality = recordOptions.quality ?? DEFAULT_QUALITY;
|
|
43
|
+
const dimensions = getDimensions(aspectRatio, quality);
|
|
44
|
+
const shouldRecord = process.env.SCREENCI_RECORDING === 'true';
|
|
45
|
+
// Screenshots honor deviceScaleFactor for higher-DPI stills.
|
|
46
|
+
const context = await browser.newContext(buildScreenCIContextOptions({
|
|
47
|
+
dimensions,
|
|
48
|
+
applyLocaleDefault: shouldRecord,
|
|
49
|
+
deviceScaleFactor: resolveDeviceScaleFactor(recordOptions, deviceScaleFactor, DEFAULT_SCREENSHOT_DEVICE_SCALE_FACTOR),
|
|
50
|
+
forwarded: {
|
|
51
|
+
colorScheme,
|
|
52
|
+
locale,
|
|
53
|
+
timezoneId,
|
|
54
|
+
userAgent,
|
|
55
|
+
geolocation,
|
|
56
|
+
permissions,
|
|
57
|
+
extraHTTPHeaders,
|
|
58
|
+
httpCredentials,
|
|
59
|
+
ignoreHTTPSErrors,
|
|
60
|
+
offline,
|
|
61
|
+
storageState,
|
|
62
|
+
baseURL,
|
|
63
|
+
bypassCSP,
|
|
64
|
+
acceptDownloads,
|
|
65
|
+
javaScriptEnabled,
|
|
66
|
+
hasTouch,
|
|
67
|
+
isMobile,
|
|
68
|
+
},
|
|
69
|
+
}));
|
|
70
|
+
instrumentContext(context);
|
|
71
|
+
try {
|
|
72
|
+
await use(context);
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
await context.close();
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
page: async ({ context, recordOptions, renderOptions, deviceScaleFactor }, use, testInfo) => {
|
|
79
|
+
const shouldRecord = process.env.SCREENCI_RECORDING === 'true';
|
|
80
|
+
const recorder = new EventRecorder(renderOptions, recordOptions);
|
|
81
|
+
if (!shouldRecord) {
|
|
82
|
+
// Preview run (`screenci test`): exercise the body without capturing.
|
|
83
|
+
const page = await context.newPage();
|
|
84
|
+
const runtimeContext = createScreenCIRuntimeContext({
|
|
85
|
+
recorder,
|
|
86
|
+
page,
|
|
87
|
+
testFilePath: testInfo.file,
|
|
88
|
+
});
|
|
89
|
+
recorder.start();
|
|
90
|
+
await withActiveRecordingContext({
|
|
91
|
+
runtimeContext,
|
|
92
|
+
page,
|
|
93
|
+
recorder,
|
|
94
|
+
unendedOverlays: 'autoEnd',
|
|
95
|
+
fn: async () => {
|
|
96
|
+
await use(page);
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
await page.close();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const aspectRatio = recordOptions.aspectRatio ?? DEFAULT_ASPECT_RATIO;
|
|
103
|
+
const quality = recordOptions.quality ?? DEFAULT_QUALITY;
|
|
104
|
+
const dimensions = getDimensions(aspectRatio, quality);
|
|
105
|
+
const dsf = resolveDeviceScaleFactor(recordOptions, deviceScaleFactor, DEFAULT_SCREENSHOT_DEVICE_SCALE_FACTOR);
|
|
106
|
+
const directoryName = escapeFileSystemPathSegment(testInfo.title);
|
|
107
|
+
const screenshotDir = join(process.cwd(), '.screenci', directoryName);
|
|
108
|
+
// Start fresh.
|
|
109
|
+
try {
|
|
110
|
+
await rm(screenshotDir, { recursive: true, force: true });
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
// Ignore if it does not exist.
|
|
114
|
+
}
|
|
115
|
+
await mkdir(screenshotDir, { recursive: true });
|
|
116
|
+
const page = await context.newPage();
|
|
117
|
+
const runtimeContext = createScreenCIRuntimeContext({
|
|
118
|
+
recorder,
|
|
119
|
+
page,
|
|
120
|
+
testFilePath: testInfo.file,
|
|
121
|
+
recordingDir: screenshotDir,
|
|
122
|
+
});
|
|
123
|
+
recorder.start();
|
|
124
|
+
try {
|
|
125
|
+
await withActiveRecordingContext({
|
|
126
|
+
runtimeContext,
|
|
127
|
+
page,
|
|
128
|
+
recorder,
|
|
129
|
+
unendedOverlays: 'autoEnd',
|
|
130
|
+
fn: async () => {
|
|
131
|
+
await use(page);
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
// The body completed successfully: capture the final page state. Capturing
|
|
135
|
+
// here (not in `finally`) mirrors the video fixture's passed-only upload:
|
|
136
|
+
// a thrown body skips capture and fails the test.
|
|
137
|
+
await page.screenshot({
|
|
138
|
+
path: join(screenshotDir, SCREENSHOT_FILE_NAME),
|
|
139
|
+
});
|
|
140
|
+
const crop = runtimeContext.crop ?? undefined;
|
|
141
|
+
const screenshot = {
|
|
142
|
+
path: SCREENSHOT_FILE_NAME,
|
|
143
|
+
width: Math.round(dimensions.width * dsf),
|
|
144
|
+
height: Math.round(dimensions.height * dsf),
|
|
145
|
+
deviceScaleFactor: dsf,
|
|
146
|
+
};
|
|
147
|
+
const configDir = process.env.SCREENCI_CONFIG_DIR ?? process.cwd();
|
|
148
|
+
// The crop (from the `crop` fixture) is a render option, so it goes into
|
|
149
|
+
// renderOptions.screenshot.crop (editable in Studio), not ScreenshotInfo.
|
|
150
|
+
await recorder.writeToFile(screenshotDir, testInfo.title, relative(configDir, testInfo.file), {
|
|
151
|
+
output: 'screenshot',
|
|
152
|
+
screenshot,
|
|
153
|
+
...(crop !== undefined && { crop }),
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
await page.close();
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
/**
|
|
162
|
+
* ScreenCI screenshot test fixture.
|
|
163
|
+
*
|
|
164
|
+
* Extended Playwright test that captures a branded still image of the final page
|
|
165
|
+
* state. Configure capture options with `screenshot.use()` or in your config.
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```ts
|
|
169
|
+
* import { screenshot, createOverlays } from 'screenci'
|
|
170
|
+
*
|
|
171
|
+
* const overlays = createOverlays({
|
|
172
|
+
* badge: { path: '../assets/new-badge.png', x: 0.72, y: 0.06, width: 0.2 },
|
|
173
|
+
* })
|
|
174
|
+
*
|
|
175
|
+
* screenshot.use({
|
|
176
|
+
* colorScheme: 'dark',
|
|
177
|
+
* recordOptions: { quality: '1440p', deviceScaleFactor: 2 },
|
|
178
|
+
* })
|
|
179
|
+
*
|
|
180
|
+
* screenshot('Dashboard hero', async ({ page, crop }) => {
|
|
181
|
+
* await page.goto('https://app.example.com/dashboard')
|
|
182
|
+
* await overlays.badge()
|
|
183
|
+
* await crop(page.getByTestId('revenue-card'), { padding: 0.06 })
|
|
184
|
+
* })
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
export const screenshot = _screenshotBase;
|
|
188
|
+
//# sourceMappingURL=screenshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../src/screenshot.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Page } from '@playwright/test';
|
|
2
|
+
import type { IEventRecorder } from './events.js';
|
|
3
|
+
import type { CropTarget, ScreenshotCropRecord } from './crop.js';
|
|
4
|
+
import type { RecordOptions, RenderOptions } from './types.js';
|
|
5
|
+
import type { StudioRenderOptionsSentinel } from './studio.js';
|
|
6
|
+
/**
|
|
7
|
+
* The screenci-specific options added to `page.screenshot()` inside a `video()`.
|
|
8
|
+
* Everything else is forwarded to Playwright's native screenshot.
|
|
9
|
+
*/
|
|
10
|
+
export type StillScreenshotOptions = {
|
|
11
|
+
/**
|
|
12
|
+
* Names the still recording produced from this capture. The recording's title
|
|
13
|
+
* is `"<video title> - <name>"`. Defaults to the `path` basename, then an
|
|
14
|
+
* auto-indexed `screenshot`, `screenshot 2`, ...
|
|
15
|
+
*/
|
|
16
|
+
name?: string;
|
|
17
|
+
/** Crop the still to a locator or pixel region (applied by the compositor). */
|
|
18
|
+
crop?: CropTarget;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Resolve the still's name: explicit `name`, else the `path` basename (without
|
|
22
|
+
* extension), else an auto-indexed fallback that stays unique within `used`.
|
|
23
|
+
* Pure and exported for testing.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveStillName(name: string | undefined, path: string | undefined, used: Set<string>): string;
|
|
26
|
+
/** Injectable side effects, so the writer can be unit tested without real I/O. */
|
|
27
|
+
export type StillCaptureDeps = {
|
|
28
|
+
/** Captures the page to `pngPath` and returns the raw bytes. */
|
|
29
|
+
capture: (pngPath: string) => Promise<Buffer>;
|
|
30
|
+
fs?: {
|
|
31
|
+
rm: (path: string) => Promise<void>;
|
|
32
|
+
mkdir: (path: string) => Promise<void>;
|
|
33
|
+
};
|
|
34
|
+
makeRecorder?: (renderOptions: RenderOptions | StudioRenderOptionsSentinel | undefined, recordOptions: RecordOptions | undefined) => IEventRecorder;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Write a standalone screenshot recording (its own `.screenci/<title>/` dir with
|
|
38
|
+
* `output: 'screenshot'`). Discovered and uploaded by the CLI exactly like a
|
|
39
|
+
* `screenshot()` fixture capture, so no rendering/backend changes are needed.
|
|
40
|
+
* Returns the captured bytes so the wrapped `page.screenshot()` can return them.
|
|
41
|
+
*/
|
|
42
|
+
export declare function writeStillRecording(params: {
|
|
43
|
+
name: string;
|
|
44
|
+
screenciDir: string;
|
|
45
|
+
dimensions: {
|
|
46
|
+
width: number;
|
|
47
|
+
height: number;
|
|
48
|
+
};
|
|
49
|
+
deviceScaleFactor: number;
|
|
50
|
+
crop?: ScreenshotCropRecord;
|
|
51
|
+
testFilePath: string | null;
|
|
52
|
+
configDir: string;
|
|
53
|
+
recordOptions: RecordOptions | undefined;
|
|
54
|
+
renderOptions: RenderOptions | StudioRenderOptionsSentinel | undefined;
|
|
55
|
+
deps: StillCaptureDeps;
|
|
56
|
+
}): Promise<Buffer>;
|
|
57
|
+
/**
|
|
58
|
+
* Wrap `page.screenshot()` so that, while recording a `video()`, each call also
|
|
59
|
+
* writes a branded still as a separate screenshot recording, then returns the
|
|
60
|
+
* native Buffer. Outside recording it strips the screenci-specific keys and
|
|
61
|
+
* delegates straight to Playwright.
|
|
62
|
+
*
|
|
63
|
+
* Bound only to the `video()` fixture's page (never the `screenshot()` fixture's),
|
|
64
|
+
* so the screenshot fixture's own implicit capture and the overlay rasterizer
|
|
65
|
+
* keep the native behavior.
|
|
66
|
+
*/
|
|
67
|
+
export declare function bindStillCaptureToPage(page: Page): void;
|
|
68
|
+
//# sourceMappingURL=stillCapture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stillCapture.d.ts","sourceRoot":"","sources":["../../src/stillCapture.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAI5C,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,aAAa,CAAA;AAEjE,OAAO,KAAK,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAOjE,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC9D,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAA;AAK9D;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,+EAA+E;IAC/E,IAAI,CAAC,EAAE,UAAU,CAAA;CAClB,CAAA;AAQD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,GAChB,MAAM,CAqBR;AAED,kFAAkF;AAClF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,gEAAgE;IAChE,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAC7C,EAAE,CAAC,EAAE;QACH,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;QACnC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;KACvC,CAAA;IACD,YAAY,CAAC,EAAE,CACb,aAAa,EAAE,aAAa,GAAG,2BAA2B,GAAG,SAAS,EACtE,aAAa,EAAE,aAAa,GAAG,SAAS,KACrC,cAAc,CAAA;CACpB,CAAA;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE;IAChD,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IAC7C,iBAAiB,EAAE,MAAM,CAAA;IACzB,IAAI,CAAC,EAAE,oBAAoB,CAAA;IAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,aAAa,GAAG,SAAS,CAAA;IACxC,aAAa,EAAE,aAAa,GAAG,2BAA2B,GAAG,SAAS,CAAA;IACtE,IAAI,EAAE,gBAAgB,CAAA;CACvB,GAAG,OAAO,CAAC,MAAM,CAAC,CAmDlB;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAqDvD"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { mkdir as fsMkdir, rm as fsRm } from 'fs/promises';
|
|
2
|
+
import { join, relative } from 'path';
|
|
3
|
+
import { getDimensions } from './dimensions.js';
|
|
4
|
+
import { escapeFileSystemPathSegment } from './fileSystemName.js';
|
|
5
|
+
import { EventRecorder } from './events.js';
|
|
6
|
+
import { resolveCrop } from './crop.js';
|
|
7
|
+
import { getScreenCIRuntimeContext } from './runtimeContext.js';
|
|
8
|
+
import { DEFAULT_VIDEO_OPTIONS, DEFAULT_ASPECT_RATIO, DEFAULT_QUALITY, } from './defaults.js';
|
|
9
|
+
/** File name of the raw page capture written beside a still's `data.json`. */
|
|
10
|
+
const SCREENSHOT_FILE_NAME = 'screenshot.png';
|
|
11
|
+
/**
|
|
12
|
+
* Resolve the still's name: explicit `name`, else the `path` basename (without
|
|
13
|
+
* extension), else an auto-indexed fallback that stays unique within `used`.
|
|
14
|
+
* Pure and exported for testing.
|
|
15
|
+
*/
|
|
16
|
+
export function resolveStillName(name, path, used) {
|
|
17
|
+
let base = name?.trim() || undefined;
|
|
18
|
+
if (base === undefined && typeof path === 'string') {
|
|
19
|
+
base =
|
|
20
|
+
path
|
|
21
|
+
.split(/[\\/]/)
|
|
22
|
+
.pop()
|
|
23
|
+
?.replace(/\.[^.]+$/, '') || undefined;
|
|
24
|
+
}
|
|
25
|
+
if (base === undefined) {
|
|
26
|
+
base = 'screenshot';
|
|
27
|
+
}
|
|
28
|
+
let candidate = base;
|
|
29
|
+
let n = 2;
|
|
30
|
+
while (used.has(candidate)) {
|
|
31
|
+
candidate = `${base} ${n}`;
|
|
32
|
+
n++;
|
|
33
|
+
}
|
|
34
|
+
used.add(candidate);
|
|
35
|
+
return candidate;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Write a standalone screenshot recording (its own `.screenci/<title>/` dir with
|
|
39
|
+
* `output: 'screenshot'`). Discovered and uploaded by the CLI exactly like a
|
|
40
|
+
* `screenshot()` fixture capture, so no rendering/backend changes are needed.
|
|
41
|
+
* Returns the captured bytes so the wrapped `page.screenshot()` can return them.
|
|
42
|
+
*/
|
|
43
|
+
export async function writeStillRecording(params) {
|
|
44
|
+
const { name, screenciDir, dimensions, deviceScaleFactor, crop, testFilePath, configDir, recordOptions, renderOptions, deps, } = params;
|
|
45
|
+
const rm = deps.fs?.rm ??
|
|
46
|
+
((path) => fsRm(path, { recursive: true, force: true }));
|
|
47
|
+
const mkdir = deps.fs?.mkdir ??
|
|
48
|
+
((path) => fsMkdir(path, { recursive: true }).then(() => undefined));
|
|
49
|
+
const makeRecorder = deps.makeRecorder ?? ((ro, rec) => new EventRecorder(ro, rec));
|
|
50
|
+
// The still is named exactly by `name`; its directory and recording title both
|
|
51
|
+
// use it directly (like a standalone screenshot() test's title).
|
|
52
|
+
const dir = join(screenciDir, escapeFileSystemPathSegment(name));
|
|
53
|
+
await rm(dir);
|
|
54
|
+
await mkdir(dir);
|
|
55
|
+
const buffer = await deps.capture(join(dir, SCREENSHOT_FILE_NAME));
|
|
56
|
+
const screenshot = {
|
|
57
|
+
path: SCREENSHOT_FILE_NAME,
|
|
58
|
+
width: Math.round(dimensions.width * deviceScaleFactor),
|
|
59
|
+
height: Math.round(dimensions.height * deviceScaleFactor),
|
|
60
|
+
deviceScaleFactor,
|
|
61
|
+
};
|
|
62
|
+
const recorder = makeRecorder(renderOptions, recordOptions);
|
|
63
|
+
recorder.start();
|
|
64
|
+
// The crop is a render option (renderOptions.screenshot.crop), passed through
|
|
65
|
+
// writeToFile rather than stored on ScreenshotInfo.
|
|
66
|
+
await recorder.writeToFile(dir, name, testFilePath !== null ? relative(configDir, testFilePath) : undefined, { output: 'screenshot', screenshot, ...(crop !== undefined && { crop }) });
|
|
67
|
+
return buffer;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Wrap `page.screenshot()` so that, while recording a `video()`, each call also
|
|
71
|
+
* writes a branded still as a separate screenshot recording, then returns the
|
|
72
|
+
* native Buffer. Outside recording it strips the screenci-specific keys and
|
|
73
|
+
* delegates straight to Playwright.
|
|
74
|
+
*
|
|
75
|
+
* Bound only to the `video()` fixture's page (never the `screenshot()` fixture's),
|
|
76
|
+
* so the screenshot fixture's own implicit capture and the overlay rasterizer
|
|
77
|
+
* keep the native behavior.
|
|
78
|
+
*/
|
|
79
|
+
export function bindStillCaptureToPage(page) {
|
|
80
|
+
const original = page.screenshot.bind(page);
|
|
81
|
+
const usedNames = new Set();
|
|
82
|
+
const wrapped = async (options) => {
|
|
83
|
+
const { name, crop: cropTarget, ...playwrightOptions } = options ?? {};
|
|
84
|
+
if (process.env.SCREENCI_RECORDING !== 'true') {
|
|
85
|
+
return original(playwrightOptions);
|
|
86
|
+
}
|
|
87
|
+
const ctx = getScreenCIRuntimeContext();
|
|
88
|
+
const recordOptions = ctx.recordOptions ?? DEFAULT_VIDEO_OPTIONS;
|
|
89
|
+
const aspectRatio = recordOptions.aspectRatio ?? DEFAULT_ASPECT_RATIO;
|
|
90
|
+
const quality = recordOptions.quality ?? DEFAULT_QUALITY;
|
|
91
|
+
const dimensions = getDimensions(aspectRatio, quality);
|
|
92
|
+
const resolvedName = resolveStillName(name, typeof playwrightOptions.path === 'string'
|
|
93
|
+
? playwrightOptions.path
|
|
94
|
+
: undefined, usedNames);
|
|
95
|
+
let crop;
|
|
96
|
+
if (cropTarget !== undefined && ctx.page !== null) {
|
|
97
|
+
crop = await resolveCrop(cropTarget, ctx.page);
|
|
98
|
+
}
|
|
99
|
+
const configDir = process.env.SCREENCI_CONFIG_DIR ?? process.cwd();
|
|
100
|
+
return writeStillRecording({
|
|
101
|
+
name: resolvedName,
|
|
102
|
+
screenciDir: join(process.cwd(), '.screenci'),
|
|
103
|
+
dimensions,
|
|
104
|
+
// The video context never applies deviceScaleFactor (video.ts), so a still
|
|
105
|
+
// captured mid-recording is at the viewport resolution (DSF 1).
|
|
106
|
+
deviceScaleFactor: 1,
|
|
107
|
+
...(crop !== undefined && { crop }),
|
|
108
|
+
testFilePath: ctx.testFilePath,
|
|
109
|
+
configDir,
|
|
110
|
+
recordOptions,
|
|
111
|
+
renderOptions: ctx.renderOptions,
|
|
112
|
+
deps: {
|
|
113
|
+
capture: (pngPath) => original({ ...playwrightOptions, path: pngPath }),
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
page.screenshot = wrapped;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=stillCapture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stillCapture.js","sourceRoot":"","sources":["../../src/stillCapture.ts"],"names":[],"mappings":"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"}
|
package/dist/src/studio.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Code opts in per concern:
|
|
6
6
|
* - `createStudioNarration('intro', 'outro')` declares cue keys whose text and
|
|
7
7
|
* voice are filled in on the Studio page.
|
|
8
|
-
* - `renderOptions:
|
|
8
|
+
* - `renderOptions: 'studio'` defers render options to Studio.
|
|
9
9
|
*
|
|
10
10
|
* On the first upload of a studio-mode video, rendering is held until the
|
|
11
11
|
* video is configured in Studio; later uploads reuse the saved configuration.
|
|
@@ -14,23 +14,20 @@
|
|
|
14
14
|
* Sentinel value for the `renderOptions` fixture/config option meaning
|
|
15
15
|
* "render options are configured in Studio".
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
17
|
+
* A plain string literal (not an object or symbol) so it survives Playwright's
|
|
18
|
+
* serialization of `use` options between the config file and test workers, and
|
|
19
|
+
* cannot collide with a real {@link import('./types.js').RenderOptions} value,
|
|
20
|
+
* which is always an object.
|
|
21
21
|
*
|
|
22
22
|
* @example
|
|
23
23
|
* ```ts
|
|
24
|
-
* import { defineConfig
|
|
24
|
+
* import { defineConfig } from 'screenci'
|
|
25
25
|
*
|
|
26
26
|
* export default defineConfig({
|
|
27
|
-
* use: { renderOptions:
|
|
27
|
+
* use: { renderOptions: 'studio' },
|
|
28
28
|
* })
|
|
29
29
|
* ```
|
|
30
30
|
*/
|
|
31
|
-
export
|
|
32
|
-
readonly __screenciStudioRenderOptions: true;
|
|
33
|
-
}>;
|
|
34
|
-
export type StudioRenderOptionsSentinel = typeof STUDIO_RENDER_OPTIONS;
|
|
31
|
+
export type StudioRenderOptionsSentinel = 'studio';
|
|
35
32
|
export declare function isStudioRenderOptions(value: unknown): value is StudioRenderOptionsSentinel;
|
|
36
33
|
//# sourceMappingURL=studio.d.ts.map
|
package/dist/src/studio.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"studio.d.ts","sourceRoot":"","sources":["../../src/studio.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;;;;;;;;;;;;;;GAiBG;AACH,
|
|
1
|
+
{"version":3,"file":"studio.d.ts","sourceRoot":"","sources":["../../src/studio.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,2BAA2B,GAAG,QAAQ,CAAA;AAElD,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,2BAA2B,CAEtC"}
|
package/dist/src/studio.js
CHANGED
|
@@ -5,35 +5,12 @@
|
|
|
5
5
|
* Code opts in per concern:
|
|
6
6
|
* - `createStudioNarration('intro', 'outro')` declares cue keys whose text and
|
|
7
7
|
* voice are filled in on the Studio page.
|
|
8
|
-
* - `renderOptions:
|
|
8
|
+
* - `renderOptions: 'studio'` defers render options to Studio.
|
|
9
9
|
*
|
|
10
10
|
* On the first upload of a studio-mode video, rendering is held until the
|
|
11
11
|
* video is configured in Studio; later uploads reuse the saved configuration.
|
|
12
12
|
*/
|
|
13
|
-
/**
|
|
14
|
-
* Sentinel value for the `renderOptions` fixture/config option meaning
|
|
15
|
-
* "render options are configured in Studio".
|
|
16
|
-
*
|
|
17
|
-
* Implemented as a frozen, JSON-safe branded object (not a string or symbol)
|
|
18
|
-
* so it survives Playwright's serialization of `use` options between the
|
|
19
|
-
* config file and test workers, and cannot collide with a real
|
|
20
|
-
* {@link import('./types.js').RenderOptions} value.
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* ```ts
|
|
24
|
-
* import { defineConfig, STUDIO_RENDER_OPTIONS } from 'screenci'
|
|
25
|
-
*
|
|
26
|
-
* export default defineConfig({
|
|
27
|
-
* use: { renderOptions: STUDIO_RENDER_OPTIONS },
|
|
28
|
-
* })
|
|
29
|
-
* ```
|
|
30
|
-
*/
|
|
31
|
-
export const STUDIO_RENDER_OPTIONS = Object.freeze({
|
|
32
|
-
__screenciStudioRenderOptions: true,
|
|
33
|
-
});
|
|
34
13
|
export function isStudioRenderOptions(value) {
|
|
35
|
-
return
|
|
36
|
-
value !== null &&
|
|
37
|
-
value.__screenciStudioRenderOptions === true);
|
|
14
|
+
return value === 'studio';
|
|
38
15
|
}
|
|
39
16
|
//# sourceMappingURL=studio.js.map
|
package/dist/src/studio.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"studio.js","sourceRoot":"","sources":["../../src/studio.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;
|
|
1
|
+
{"version":3,"file":"studio.js","sourceRoot":"","sources":["../../src/studio.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAsBH,MAAM,UAAU,qBAAqB,CACnC,KAAc;IAEd,OAAO,KAAK,KAAK,QAAQ,CAAA;AAC3B,CAAC"}
|