Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(api): add page.emulateMedia{Type,Features} #5012

Merged
merged 6 commits into from Oct 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
76 changes: 73 additions & 3 deletions docs/api.md
Expand Up @@ -108,7 +108,9 @@
* [page.coverage](#pagecoverage)
* [page.deleteCookie(...cookies)](#pagedeletecookiecookies)
* [page.emulate(options)](#pageemulateoptions)
* [page.emulateMedia(mediaType)](#pageemulatemediamediatype)
* [page.emulateMedia(type)](#pageemulatemediatype)
* [page.emulateMediaFeatures(features)](#pageemulatemediafeaturesfeatures)
* [page.emulateMediaType(type)](#pageemulatemediatypetype)
* [page.evaluate(pageFunction[, ...args])](#pageevaluatepagefunction-args)
* [page.evaluateHandle(pageFunction[, ...args])](#pageevaluatehandlepagefunction-args)
* [page.evaluateOnNewDocument(pageFunction[, ...args])](#pageevaluateonnewdocumentpagefunction-args)
Expand Down Expand Up @@ -1276,10 +1278,78 @@ puppeteer.launch().then(async browser => {

List of all available devices is available in the source code: [DeviceDescriptors.js](https://github.com/GoogleChrome/puppeteer/blob/master/lib/DeviceDescriptors.js).

#### page.emulateMedia(mediaType)
- `mediaType` <?[string]> Changes the CSS media type of the page. The only allowed values are `'screen'`, `'print'` and `null`. Passing `null` disables media emulation.
#### page.emulateMedia(type)
- `type` <?[string]> Changes the CSS media type of the page. The only allowed values are `'screen'`, `'print'` and `null`. Passing `null` disables CSS media emulation.
- returns: <[Promise]>

**Note:** This method is deprecated, and only kept around as an alias for backwards compatibility. Use [`page.emulateMediaType(type)`](#pageemulatemediatypetype) instead.

#### page.emulateMediaFeatures(features)
- `features` <?[Array]<[Object]>> Given an array of media feature objects, emulates CSS media features on the page. Each media feature object must have the following properties:
- `name` <[string]> The CSS media feature name. Supported names are `'prefers-colors-scheme'` and `'prefers-reduced-motion'`.
- `value` <[string]> The value for the given CSS media feature.
- returns: <[Promise]>

```js
await page.emulateMediaFeatures([{ name: 'prefers-color-scheme', value: 'dark' }]);
await page.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches));
// → true
await page.evaluate(() => matchMedia('(prefers-color-scheme: light)').matches));
// → false
await page.evaluate(() => matchMedia('(prefers-color-scheme: no-preference)').matches));
// → false

await page.emulateMediaFeatures([{ name: 'prefers-reduced-motion', value: 'reduce' }]);
await page.evaluate(() => matchMedia('(prefers-reduced-motion: reduce)').matches));
// → true
await page.evaluate(() => matchMedia('(prefers-color-scheme: no-preference)').matches));
// → false

await page.emulateMediaFeatures([{ name: 'prefers-reduced-motion', value: 'reduce' }]);
await page.evaluate(() => matchMedia('(prefers-reduced-motion: reduce)').matches));
// → true
await page.evaluate(() => matchMedia('(prefers-color-scheme: no-preference)').matches));
// → false
Comment on lines +1302 to +1312
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems these blocks are duplicate.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vsemozhetbyt Wanna submit a patch?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hope it's right: #5072


await page.emulateMediaFeatures([
{ name: 'prefers-color-scheme', value: 'dark' },
{ name: 'prefers-reduced-motion', value: 'reduce' },
]);
await page.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches));
// → true
await page.evaluate(() => matchMedia('(prefers-color-scheme: light)').matches));
// → false
await page.evaluate(() => matchMedia('(prefers-color-scheme: no-preference)').matches));
// → false
await page.evaluate(() => matchMedia('(prefers-reduced-motion: reduce)').matches));
// → true
await page.evaluate(() => matchMedia('(prefers-color-scheme: no-preference)').matches));
// → false
```

#### page.emulateMediaType(type)
- `type` <?[string]> Changes the CSS media type of the page. The only allowed values are `'screen'`, `'print'` and `null`. Passing `null` disables CSS media emulation.
- returns: <[Promise]>

```js
await page.evaluate(() => matchMedia('screen').matches));
// → true
await page.evaluate(() => matchMedia('print').matches));
// → true

await page.emulateMediaType('print');
await page.evaluate(() => matchMedia('screen').matches));
// → false
await page.evaluate(() => matchMedia('print').matches));
// → true

await page.emulateMediaType(null);
await page.evaluate(() => matchMedia('screen').matches));
// → true
await page.evaluate(() => matchMedia('print').matches));
// → true
```

#### page.evaluate(pageFunction[, ...args])
- `pageFunction` <[function]|[string]> Function to be evaluated in the page context
- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
Expand Down
11 changes: 7 additions & 4 deletions experimental/puppeteer-firefox/lib/Page.js
Expand Up @@ -150,11 +150,11 @@ class Page extends EventEmitter {
}

/**
* @param {?string} mediaType
* @param {?string} type
*/
async emulateMedia(mediaType) {
assert(mediaType === 'screen' || mediaType === 'print' || mediaType === null, 'Unsupported media type: ' + mediaType);
await this._session.send('Page.setEmulatedMedia', {media: mediaType || ''});
async emulateMediaType(type) {
assert(type === 'screen' || type === 'print' || type === null, 'Unsupported media type: ' + type);
await this._session.send('Page.setEmulatedMedia', {media: type || ''});
}

/**
Expand Down Expand Up @@ -747,6 +747,9 @@ class Page extends EventEmitter {
}
}

// Expose alias for deprecated method.
Page.prototype.emulateMedia = Page.prototype.emulateMediaType;

class ConsoleMessage {
/**
* @param {string} type
Expand Down
33 changes: 29 additions & 4 deletions lib/Page.js
Expand Up @@ -801,11 +801,27 @@ class Page extends EventEmitter {
}

/**
* @param {?string} mediaType
* @param {?string} type
*/
async emulateMedia(mediaType) {
mathiasbynens marked this conversation as resolved.
Show resolved Hide resolved
assert(mediaType === 'screen' || mediaType === 'print' || mediaType === null, 'Unsupported media type: ' + mediaType);
await this._client.send('Emulation.setEmulatedMedia', {media: mediaType || ''});
async emulateMediaType(type) {
assert(type === 'screen' || type === 'print' || type === null, 'Unsupported media type: ' + type);
await this._client.send('Emulation.setEmulatedMedia', {media: type || ''});
}

/**
* @param {?Array<MediaFeature>} features
*/
async emulateMediaFeatures(features) {
if (features === null)
await this._client.send('Emulation.setEmulatedMedia', {features: null});
if (Array.isArray(features)) {
features.every(mediaFeature => {
const name = mediaFeature.name;
assert(/^prefers-(?:color-scheme|reduced-motion)$/.test(name), 'Unsupported media feature: ' + name);
szuend marked this conversation as resolved.
Show resolved Hide resolved
return true;
});
await this._client.send('Emulation.setEmulatedMedia', {features: features});
}
}

/**
Expand Down Expand Up @@ -1116,6 +1132,9 @@ class Page extends EventEmitter {
}
}

// Expose alias for deprecated method.
Page.prototype.emulateMedia = Page.prototype.emulateMediaType;

/**
* @typedef {Object} PDFOptions
* @property {number=} scale
Expand Down Expand Up @@ -1161,6 +1180,12 @@ class Page extends EventEmitter {
* @property {string=} encoding
*/

/**
* @typedef {Object} MediaFeature
* @property {string} name
* @property {string} value
*/

/** @type {!Set<string>} */
const supportedMetrics = new Set([
'Timestamp',
Expand Down
61 changes: 52 additions & 9 deletions test/emulation.spec.js
Expand Up @@ -98,20 +98,63 @@ module.exports.addTests = function({testRunner, expect, puppeteer}) {
});

describe('Page.emulateMedia', function() {
it('should be an alias for Page.emulateMediaType', async({page, server}) => {
expect(page.emulateMedia).toEqual(page.emulateMediaType);
});
});

describe('Page.emulateMediaType', function() {
it('should work', async({page, server}) => {
expect(await page.evaluate(() => window.matchMedia('screen').matches)).toBe(true);
expect(await page.evaluate(() => window.matchMedia('print').matches)).toBe(false);
await page.emulateMedia('print');
expect(await page.evaluate(() => window.matchMedia('screen').matches)).toBe(false);
expect(await page.evaluate(() => window.matchMedia('print').matches)).toBe(true);
await page.emulateMedia(null);
expect(await page.evaluate(() => window.matchMedia('screen').matches)).toBe(true);
expect(await page.evaluate(() => window.matchMedia('print').matches)).toBe(false);
expect(await page.evaluate(() => matchMedia('screen').matches)).toBe(true);
expect(await page.evaluate(() => matchMedia('print').matches)).toBe(false);
await page.emulateMediaType('print');
expect(await page.evaluate(() => matchMedia('screen').matches)).toBe(false);
expect(await page.evaluate(() => matchMedia('print').matches)).toBe(true);
await page.emulateMediaType(null);
expect(await page.evaluate(() => matchMedia('screen').matches)).toBe(true);
expect(await page.evaluate(() => matchMedia('print').matches)).toBe(false);
});
it('should throw in case of bad argument', async({page, server}) => {
let error = null;
await page.emulateMedia('bad').catch(e => error = e);
await page.emulateMediaType('bad').catch(e => error = e);
expect(error.message).toBe('Unsupported media type: bad');
});
});

describe_fails_ffox('Page.emulateMediaFeatures', function() {
it('should work', async({page, server}) => {
await page.emulateMediaFeatures([
{ name: 'prefers-reduced-motion', value: 'reduce' },
]);
expect(await page.evaluate(() => matchMedia('(prefers-reduced-motion: reduce)').matches)).toBe(true);
expect(await page.evaluate(() => matchMedia('(prefers-reduced-motion: no-preference)').matches)).toBe(false);
await page.emulateMediaFeatures([
{ name: 'prefers-color-scheme', value: 'light' },
]);
expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: light)').matches)).toBe(true);
expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(false);
expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: no-preference)').matches)).toBe(false);
await page.emulateMediaFeatures([
{ name: 'prefers-color-scheme', value: 'dark' },
]);
expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(true);
expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: light)').matches)).toBe(false);
expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: no-preference)').matches)).toBe(false);
await page.emulateMediaFeatures([
{ name: 'prefers-reduced-motion', value: 'reduce' },
{ name: 'prefers-color-scheme', value: 'light' },
]);
expect(await page.evaluate(() => matchMedia('(prefers-reduced-motion: reduce)').matches)).toBe(true);
expect(await page.evaluate(() => matchMedia('(prefers-reduced-motion: no-preference)').matches)).toBe(false);
expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: light)').matches)).toBe(true);
expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(false);
expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: no-preference)').matches)).toBe(false);
});
it('should throw in case of bad argument', async({page, server}) => {
let error = null;
await page.emulateMediaFeatures([{ name: 'bad', value: '' }]).catch(e => error = e);
expect(error.message).toBe('Unsupported media feature: bad');
});
});

};
1 change: 1 addition & 0 deletions test/test.js
Expand Up @@ -73,6 +73,7 @@ beforeEach(async({server, httpsServer}) => {
});

const CHROMIUM_NO_COVERAGE = new Set([
'page.emulateMedia', // Legacy alias for `page.emulateMediaType`.
]);

if (process.env.BROWSER === 'firefox') {
Expand Down