fix(platform) instanceof bug between execution contexts of RegExp object (#1048)

First encountered at jest-playwright repo:
https://github.com/mmarkelov/jest-playwright/issues/38

Solution based on:
https://stackoverflow.com/questions/4339288/typeof-for-regexp#comment4724685_4339350
This commit is contained in:
aesyondu 2020-02-25 10:32:17 +08:00 committed by GitHub
parent a6c3735b9d
commit fdfec8eb2a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 44 additions and 3 deletions

View file

@ -98,6 +98,10 @@ class Helper {
return typeof obj === 'number' || obj instanceof Number;
}
static isRegExp(obj: any): obj is RegExp {
return obj instanceof RegExp || Object.prototype.toString.call(obj) === '[object RegExp]';
}
static isObject(obj: any): obj is NonNullable<object> {
return typeof obj === 'object' && obj !== null;
}

View file

@ -358,7 +358,7 @@ export class Page extends platform.EventEmitter {
async waitForRequest(urlOrPredicate: string | RegExp | ((r: network.Request) => boolean), options: types.TimeoutOptions = {}): Promise<network.Request> {
const { timeout = this._timeoutSettings.timeout() } = options;
return helper.waitForEvent(this, Events.Page.Request, (request: network.Request) => {
if (helper.isString(urlOrPredicate) || urlOrPredicate instanceof RegExp)
if (helper.isString(urlOrPredicate) || helper.isRegExp(urlOrPredicate))
return platform.urlMatches(request.url(), urlOrPredicate);
return urlOrPredicate(request);
}, timeout, this._disconnectedPromise);
@ -367,7 +367,7 @@ export class Page extends platform.EventEmitter {
async waitForResponse(urlOrPredicate: string | RegExp | ((r: network.Response) => boolean), options: types.TimeoutOptions = {}): Promise<network.Response> {
const { timeout = this._timeoutSettings.timeout() } = options;
return helper.waitForEvent(this, Events.Page.Response, (response: network.Response) => {
if (helper.isString(urlOrPredicate) || urlOrPredicate instanceof RegExp)
if (helper.isString(urlOrPredicate) || helper.isRegExp(urlOrPredicate))
return platform.urlMatches(response.url(), urlOrPredicate);
return urlOrPredicate(response);
}, timeout, this._disconnectedPromise);

View file

@ -222,7 +222,7 @@ export function urlMatches(urlString: string, match: types.URLMatch | undefined)
return true;
if (helper.isString(match))
match = helper.globToRegex(match);
if (match instanceof RegExp)
if (helper.isRegExp(match))
return match.test(urlString);
if (typeof match === 'string' && match === urlString)
return true;

View file

@ -19,6 +19,7 @@ const fs = require('fs');
const path = require('path');
const { helper } = require('../lib/helper');
const utils = require('./utils');
const vm = require('vm');
/**
* @type {PageTestSuite}
@ -618,6 +619,28 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
expect(helper.globToRegex('**/*.{png,jpg,jpeg}').test('https://localhost:8080/c.css')).toBeFalsy();
});
});
describe('regexp', function() {
it('should work with regular expression passed from a different context', async({page, server}) => {
const ctx = vm.createContext();
const regexp = vm.runInContext('new RegExp("empty\\.html")', ctx);
await page.route(regexp, request => {
expect(request.url()).toContain('empty.html');
expect(request.headers()['user-agent']).toBeTruthy();
expect(request.method()).toBe('GET');
expect(request.postData()).toBe(undefined);
expect(request.isNavigationRequest()).toBe(true);
expect(request.resourceType()).toBe('document');
expect(request.frame() === page.mainFrame()).toBe(true);
expect(request.frame().url()).toBe('about:blank');
request.continue();
});
const response = await page.goto(server.EMPTY_PAGE);
expect(response.ok()).toBe(true);
});
});
};
/**

View file

@ -18,6 +18,7 @@ const fs = require('fs');
const path = require('path');
const utils = require('./utils');
const {waitEvent} = utils;
const vm = require('vm');
/**
* @type {PageTestSuite}
@ -309,6 +310,19 @@ module.exports.describe = function({testRunner, expect, headless, playwright, FF
]);
expect(request.url()).toBe(server.PREFIX + '/digits/1.png');
});
it('should work with url match regular expression from a different context', async({page, server}) => {
const ctx = vm.createContext();
const regexp = vm.runInContext('new RegExp(/digits\\/\\d\\.png/)', ctx);
await page.goto(server.EMPTY_PAGE);
const [request] = await Promise.all([
page.waitForRequest(regexp),
page.evaluate(() => {
fetch('/digits/1.png');
})
]);
expect(request.url()).toBe(server.PREFIX + '/digits/1.png');
});
});
describe('Page.waitForResponse', function() {