mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
feat(urlmatch): support url matching in waitForNavigation (#300)
This commit is contained in:
parent
1c2b6444e9
commit
3669dad243
@ -42,6 +42,8 @@ export type NavigateOptions = {
|
|||||||
waitUntil?: LifecycleEvent | LifecycleEvent[],
|
waitUntil?: LifecycleEvent | LifecycleEvent[],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type WaitForNavigationOptions = NavigateOptions & types.URLMatch;
|
||||||
|
|
||||||
export type GotoOptions = NavigateOptions & {
|
export type GotoOptions = NavigateOptions & {
|
||||||
referer?: string,
|
referer?: string,
|
||||||
};
|
};
|
||||||
@ -284,13 +286,11 @@ export class Frame {
|
|||||||
this._parentFrame._childFrames.add(this);
|
this._parentFrame._childFrames.add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
async goto(url: string, options: GotoOptions = {}): Promise<network.Response | null> {
|
async goto(url: string, options?: GotoOptions): Promise<network.Response | null> {
|
||||||
const {
|
let referer = (this._page._state.extraHTTPHeaders || {})['referer'];
|
||||||
referer = (this._page._state.extraHTTPHeaders || {})['referer'],
|
if (options && options.referer !== undefined)
|
||||||
waitUntil = (['load'] as LifecycleEvent[]),
|
referer = options.referer;
|
||||||
timeout = this._page._timeoutSettings.navigationTimeout(),
|
const watcher = new LifecycleWatcher(this, options, false /* supportUrlMatch */);
|
||||||
} = options;
|
|
||||||
const watcher = new LifecycleWatcher(this, waitUntil, timeout);
|
|
||||||
|
|
||||||
let navigateResult: GotoResult;
|
let navigateResult: GotoResult;
|
||||||
const navigate = async () => {
|
const navigate = async () => {
|
||||||
@ -323,12 +323,8 @@ export class Frame {
|
|||||||
return watcher.navigationResponse();
|
return watcher.navigationResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForNavigation(options: NavigateOptions = {}): Promise<network.Response | null> {
|
async waitForNavigation(options?: WaitForNavigationOptions): Promise<network.Response | null> {
|
||||||
const {
|
const watcher = new LifecycleWatcher(this, options, true /* supportUrlMatch */);
|
||||||
waitUntil = (['load'] as LifecycleEvent[]),
|
|
||||||
timeout = this._page._timeoutSettings.navigationTimeout(),
|
|
||||||
} = options;
|
|
||||||
const watcher = new LifecycleWatcher(this, waitUntil, timeout);
|
|
||||||
const error = await Promise.race([
|
const error = await Promise.race([
|
||||||
watcher.timeoutOrTerminationPromise,
|
watcher.timeoutOrTerminationPromise,
|
||||||
watcher.sameDocumentNavigationPromise,
|
watcher.sameDocumentNavigationPromise,
|
||||||
@ -430,11 +426,7 @@ export class Frame {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async setContent(html: string, options: NavigateOptions = {}): Promise<void> {
|
async setContent(html: string, options?: NavigateOptions): Promise<void> {
|
||||||
const {
|
|
||||||
waitUntil = (['load'] as LifecycleEvent[]),
|
|
||||||
timeout = this._page._timeoutSettings.navigationTimeout(),
|
|
||||||
} = options;
|
|
||||||
const context = await this._utilityContext();
|
const context = await this._utilityContext();
|
||||||
if (this._page._delegate.needsLifecycleResetOnSetContent())
|
if (this._page._delegate.needsLifecycleResetOnSetContent())
|
||||||
this._firedLifecycleEvents.clear();
|
this._firedLifecycleEvents.clear();
|
||||||
@ -443,7 +435,7 @@ export class Frame {
|
|||||||
document.write(html);
|
document.write(html);
|
||||||
document.close();
|
document.close();
|
||||||
}, html);
|
}, html);
|
||||||
const watcher = new LifecycleWatcher(this, waitUntil, timeout);
|
const watcher = new LifecycleWatcher(this, options, false /* supportUrlMatch */);
|
||||||
const error = await Promise.race([
|
const error = await Promise.race([
|
||||||
watcher.timeoutOrTerminationPromise,
|
watcher.timeoutOrTerminationPromise,
|
||||||
watcher.lifecyclePromise,
|
watcher.lifecyclePromise,
|
||||||
@ -869,14 +861,22 @@ class LifecycleWatcher {
|
|||||||
private _hasSameDocumentNavigation: boolean;
|
private _hasSameDocumentNavigation: boolean;
|
||||||
private _targetUrl?: string;
|
private _targetUrl?: string;
|
||||||
private _expectedDocumentId?: string;
|
private _expectedDocumentId?: string;
|
||||||
|
private _urlMatch?: types.URLMatch;
|
||||||
|
|
||||||
constructor(frame: Frame, waitUntil: LifecycleEvent | LifecycleEvent[], timeout: number) {
|
constructor(frame: Frame, options: WaitForNavigationOptions | undefined, supportUrlMatch: boolean) {
|
||||||
if (Array.isArray(waitUntil))
|
options = options || {};
|
||||||
waitUntil = waitUntil.slice();
|
let {
|
||||||
else if (typeof waitUntil === 'string')
|
waitUntil = (['load'] as LifecycleEvent[]),
|
||||||
|
timeout = frame._page._timeoutSettings.navigationTimeout()
|
||||||
|
} = options;
|
||||||
|
if (!Array.isArray(waitUntil))
|
||||||
waitUntil = [waitUntil];
|
waitUntil = [waitUntil];
|
||||||
if (waitUntil.some(e => !kLifecycleEvents.has(e)))
|
for (const event of waitUntil) {
|
||||||
throw new Error('Unsupported waitUntil option');
|
if (!kLifecycleEvents.has(event))
|
||||||
|
throw new Error(`Unsupported waitUntil option ${String(event)}`);
|
||||||
|
}
|
||||||
|
if (supportUrlMatch)
|
||||||
|
this._urlMatch = options;
|
||||||
this._expectedLifecycle = waitUntil.slice();
|
this._expectedLifecycle = waitUntil.slice();
|
||||||
this._frame = frame;
|
this._frame = frame;
|
||||||
this.sameDocumentNavigationPromise = new Promise(f => this._sameDocumentNavigationCompleteCallback = f);
|
this.sameDocumentNavigationPromise = new Promise(f => this._sameDocumentNavigationCompleteCallback = f);
|
||||||
@ -892,7 +892,12 @@ class LifecycleWatcher {
|
|||||||
this._checkLifecycleComplete();
|
this._checkLifecycleComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _urlMatches(urlString: string): boolean {
|
||||||
|
return !this._urlMatch || helper.urlMatches(urlString, this._urlMatch);
|
||||||
|
}
|
||||||
|
|
||||||
setExpectedDocumentId(documentId: string, url: string) {
|
setExpectedDocumentId(documentId: string, url: string) {
|
||||||
|
assert(!this._urlMatch, 'Should not have url match when expecting a particular navigation');
|
||||||
this._expectedDocumentId = documentId;
|
this._expectedDocumentId = documentId;
|
||||||
this._targetUrl = url;
|
this._targetUrl = url;
|
||||||
if (this._navigationRequest && this._navigationRequest._documentId !== documentId)
|
if (this._navigationRequest && this._navigationRequest._documentId !== documentId)
|
||||||
@ -916,7 +921,7 @@ class LifecycleWatcher {
|
|||||||
|
|
||||||
_onNavigationRequest(frame: Frame, request: network.Request) {
|
_onNavigationRequest(frame: Frame, request: network.Request) {
|
||||||
assert(request._documentId);
|
assert(request._documentId);
|
||||||
if (frame !== this._frame)
|
if (frame !== this._frame || !this._urlMatches(request.url()))
|
||||||
return;
|
return;
|
||||||
if (this._expectedDocumentId === undefined || this._expectedDocumentId === request._documentId) {
|
if (this._expectedDocumentId === undefined || this._expectedDocumentId === request._documentId) {
|
||||||
this._navigationRequest = request;
|
this._navigationRequest = request;
|
||||||
@ -926,7 +931,7 @@ class LifecycleWatcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_onCommittedNewDocumentNavigation(frame: Frame) {
|
_onCommittedNewDocumentNavigation(frame: Frame) {
|
||||||
if (frame === this._frame && this._expectedDocumentId === undefined) {
|
if (frame === this._frame && this._expectedDocumentId === undefined && this._urlMatches(frame.url())) {
|
||||||
this._expectedDocumentId = frame._lastDocumentId;
|
this._expectedDocumentId = frame._lastDocumentId;
|
||||||
this._targetUrl = frame.url();
|
this._targetUrl = frame.url();
|
||||||
}
|
}
|
||||||
|
@ -297,7 +297,7 @@ export class Page extends EventEmitter {
|
|||||||
return waitPromise;
|
return waitPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
waitForNavigation(options?: frames.NavigateOptions): Promise<network.Response | null> {
|
async waitForNavigation(options?: frames.WaitForNavigationOptions): Promise<network.Response | null> {
|
||||||
return this.mainFrame().waitForNavigation(options);
|
return this.mainFrame().waitForNavigation(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -582,6 +582,40 @@ module.exports.describe = function({testRunner, expect, playwright, FFOX, CHROME
|
|||||||
navigationPromise
|
navigationPromise
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
it('should work with url match', async({page, server}) => {
|
||||||
|
let response1 = null;
|
||||||
|
const response1Promise = page.waitForNavigation({ url: /one-style\.html/ }).then(response => response1 = response);
|
||||||
|
let response2 = null;
|
||||||
|
const response2Promise = page.waitForNavigation({ pathname: '/frame.html' }).then(response => response2 = response);
|
||||||
|
let response3 = null;
|
||||||
|
const response3Promise = page.waitForNavigation({ searchParams: { 'foo': 'bar' }, strictSearchParams: true }).then(response => response3 = response);
|
||||||
|
expect(response1).toBe(null);
|
||||||
|
expect(response2).toBe(null);
|
||||||
|
expect(response3).toBe(null);
|
||||||
|
await page.goto(server.EMPTY_PAGE);
|
||||||
|
expect(response1).toBe(null);
|
||||||
|
expect(response2).toBe(null);
|
||||||
|
expect(response3).toBe(null);
|
||||||
|
await page.goto(server.PREFIX + '/frame.html');
|
||||||
|
expect(response1).toBe(null);
|
||||||
|
await response2Promise;
|
||||||
|
expect(response2).not.toBe(null);
|
||||||
|
expect(response3).toBe(null);
|
||||||
|
await page.goto(server.PREFIX + '/one-style.html');
|
||||||
|
await response1Promise;
|
||||||
|
expect(response1).not.toBe(null);
|
||||||
|
expect(response2).not.toBe(null);
|
||||||
|
expect(response3).toBe(null);
|
||||||
|
await page.goto(server.PREFIX + '/frame.html?foo=bar');
|
||||||
|
await response3Promise;
|
||||||
|
expect(response1).not.toBe(null);
|
||||||
|
expect(response2).not.toBe(null);
|
||||||
|
expect(response3).not.toBe(null);
|
||||||
|
await page.goto(server.PREFIX + '/empty.html');
|
||||||
|
expect(response1.url()).toBe(server.PREFIX + '/one-style.html');
|
||||||
|
expect(response2.url()).toBe(server.PREFIX + '/frame.html');
|
||||||
|
expect(response3.url()).toBe(server.PREFIX + '/frame.html?foo=bar');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Page.goBack', function() {
|
describe('Page.goBack', function() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user