Skip to content

Commit

Permalink
Merge pull request #1197 from capricorn86/task/1196-add-support-for-b…
Browse files Browse the repository at this point in the history
…rowserpageviewport

#466@trivial: Adds support for BrowserFrame.viewport.
  • Loading branch information
capricorn86 authored Jan 11, 2024
2 parents 1be6f62 + 91b1df5 commit 8775bde
Show file tree
Hide file tree
Showing 34 changed files with 504 additions and 165 deletions.
3 changes: 3 additions & 0 deletions packages/happy-dom/src/PropertySymbol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,6 @@ export const width = Symbol('width');
export const window = Symbol('window');
export const windowResizeListener = Symbol('windowResizeListener');
export const mutationObservers = Symbol('mutationObservers');
export const openerFrame = Symbol('openerFrame');
export const openerWindow = Symbol('openerFrame');
export const popup = Symbol('popup');
6 changes: 2 additions & 4 deletions packages/happy-dom/src/browser/Browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import IOptionalBrowserSettings from './types/IOptionalBrowserSettings.js';
import BrowserSettingsFactory from './BrowserSettingsFactory.js';
import BrowserPage from './BrowserPage.js';
import IBrowser from './types/IBrowser.js';
import BrowserFrame from './BrowserFrame.js';

/**
* Browser.
Expand Down Expand Up @@ -94,13 +93,12 @@ export default class Browser implements IBrowser {
/**
* Creates a new page.
*
* @param [opener] Opener.
* @returns Page.
*/
public newPage(opener?: BrowserFrame): BrowserPage {
public newPage(): BrowserPage {
if (this.contexts.length === 0) {
throw new Error('No default context. The browser has been closed.');
}
return this.contexts[0].newPage(opener);
return this.contexts[0].newPage();
}
}
5 changes: 1 addition & 4 deletions packages/happy-dom/src/browser/BrowserContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import ICookieContainer from '../cookie/types/ICookieContainer.js';
import ResponseCache from '../fetch/cache/response/ResponseCache.js';
import IResponseCache from '../fetch/cache/response/IResponseCache.js';
import Browser from './Browser.js';
import BrowserFrame from './BrowserFrame.js';
import BrowserPage from './BrowserPage.js';
import IBrowserContext from './types/IBrowserContext.js';
import IPreflightResponseCache from '../fetch/cache/preflight/IPreflightResponseCache.js';
Expand Down Expand Up @@ -80,12 +79,10 @@ export default class BrowserContext implements IBrowserContext {
/**
* Creates a new page.
*
* @param [opener] Opener.
* @returns Page.
*/
public newPage(opener?: BrowserFrame): BrowserPage {
public newPage(): BrowserPage {
const page = new BrowserPage(this);
(<BrowserFrame | null>(<unknown>page.mainFrame.opener)) = opener || null;
this.pages.push(page);
return page;
}
Expand Down
6 changes: 5 additions & 1 deletion packages/happy-dom/src/browser/BrowserFrame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import * as PropertySymbol from '../PropertySymbol.js';
import AsyncTaskManager from '../async-task-manager/AsyncTaskManager.js';
import IBrowserFrame from './types/IBrowserFrame.js';
import BrowserWindow from '../window/BrowserWindow.js';
import IBrowserWindow from '../window/IBrowserWindow.js';
import ICrossOriginBrowserWindow from '../window/ICrossOriginBrowserWindow.js';
import Location from '../location/Location.js';
import IResponse from '../fetch/types/IResponse.js';
import IGoToOptions from './types/IGoToOptions.js';
Expand All @@ -21,12 +23,14 @@ import IDocument from '../nodes/document/IDocument.js';
export default class BrowserFrame implements IBrowserFrame {
public readonly childFrames: BrowserFrame[] = [];
public readonly parentFrame: BrowserFrame | null = null;
public readonly opener: BrowserFrame | null = null;
public readonly page: BrowserPage;
public readonly window: BrowserWindow;
public [PropertySymbol.asyncTaskManager] = new AsyncTaskManager();
public [PropertySymbol.exceptionObserver]: BrowserFrameExceptionObserver | null = null;
public [PropertySymbol.listeners]: { navigation: Array<() => void> } = { navigation: [] };
public [PropertySymbol.openerFrame]: IBrowserFrame | null = null;
public [PropertySymbol.openerWindow]: IBrowserWindow | ICrossOriginBrowserWindow | null = null;
public [PropertySymbol.popup] = false;

/**
* Constructor.
Expand Down
18 changes: 15 additions & 3 deletions packages/happy-dom/src/browser/BrowserPage.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import VirtualConsolePrinter from '../console/VirtualConsolePrinter.js';
import IBrowserPageViewport from './types/IBrowserPageViewport.js';
import BrowserFrame from './BrowserFrame.js';
import BrowserContext from './BrowserContext.js';
import VirtualConsole from '../console/VirtualConsole.js';
Expand All @@ -9,6 +8,10 @@ import { Script } from 'vm';
import IGoToOptions from './types/IGoToOptions.js';
import IResponse from '../fetch/types/IResponse.js';
import IReloadOptions from './types/IReloadOptions.js';
import IBrowserPageViewport from './types/IBrowserPageViewport.js';
import IOptionalBrowserPageViewport from './types/IOptionalBrowserPageViewport.js';
import DefaultBrowserPageViewport from './DefaultBrowserPageViewport.js';
import Event from '../event/Event.js';

/**
* Browser page.
Expand All @@ -18,6 +21,7 @@ export default class BrowserPage implements IBrowserPage {
public readonly mainFrame: BrowserFrame;
public readonly context: BrowserContext;
public readonly console: Console;
public readonly viewport: IBrowserPageViewport = Object.assign({}, DefaultBrowserPageViewport);

/**
* Constructor.
Expand Down Expand Up @@ -114,8 +118,16 @@ export default class BrowserPage implements IBrowserPage {
*
* @param viewport Viewport.
*/
public setViewport(viewport: IBrowserPageViewport): void {
BrowserPageUtility.setViewport(this, viewport);
public setViewport(viewport: IOptionalBrowserPageViewport): void {
const previousViewport = Object.assign({}, this.viewport);
Object.assign(this.viewport, viewport);
if (
previousViewport.width !== this.viewport.width ||
previousViewport.height !== this.viewport.height ||
previousViewport.devicePixelRatio !== this.viewport.devicePixelRatio
) {
this.mainFrame.window.dispatchEvent(new Event('resize'));
}
}

/**
Expand Down
7 changes: 7 additions & 0 deletions packages/happy-dom/src/browser/DefaultBrowserPageViewport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import IBrowserPageViewport from './types/IBrowserPageViewport.js';

export default <IBrowserPageViewport>{
width: 1024,
height: 768,
devicePixelRatio: 1
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import BrowserSettingsFactory from '../BrowserSettingsFactory.js';
import DetachedBrowserPage from './DetachedBrowserPage.js';
import IBrowser from '../types/IBrowser.js';
import IBrowserFrame from '../types/IBrowserFrame.js';
import DetachedBrowserFrame from './DetachedBrowserFrame.js';
import IBrowserWindow from '../../window/IBrowserWindow.js';

/**
Expand Down Expand Up @@ -101,13 +100,12 @@ export default class DetachedBrowser implements IBrowser {
/**
* Creates a new page.
*
* @param [opener] Opener.
* @returns Page.
*/
public newPage(opener?: DetachedBrowserFrame): DetachedBrowserPage {
public newPage(): DetachedBrowserPage {
if (this.contexts.length === 0) {
throw new Error('No default context. The browser has been closed.');
}
return this.contexts[0].newPage(opener);
return this.contexts[0].newPage();
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import DetachedBrowser from './DetachedBrowser.js';
import DetachedBrowserPage from './DetachedBrowserPage.js';
import IBrowserContext from '../types/IBrowserContext.js';
import DetachedBrowserFrame from './DetachedBrowserFrame.js';
import ICookieContainer from '../../cookie/types/ICookieContainer.js';
import CookieContainer from '../../cookie/CookieContainer.js';
import ResponseCache from '../../fetch/cache/response/ResponseCache.js';
Expand Down Expand Up @@ -85,9 +84,8 @@ export default class DetachedBrowserContext implements IBrowserContext {
* @param [opener] Opener.
* @returns Page.
*/
public newPage(opener?: DetachedBrowserFrame): DetachedBrowserPage {
public newPage(): DetachedBrowserPage {
const page = new DetachedBrowserPage(this);
(<DetachedBrowserFrame | null>(<unknown>page.mainFrame.opener)) = opener || null;
this.pages.push(page);
return page;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,23 @@ import IReloadOptions from '../types/IReloadOptions.js';
import BrowserErrorCaptureEnum from '../enums/BrowserErrorCaptureEnum.js';
import BrowserFrameExceptionObserver from '../utilities/BrowserFrameExceptionObserver.js';
import IDocument from '../../nodes/document/IDocument.js';
import ICrossOriginBrowserWindow from '../../window/ICrossOriginBrowserWindow.js';

/**
* Browser frame used when constructing a Window instance without a browser.
*/
export default class DetachedBrowserFrame implements IBrowserFrame {
public readonly childFrames: DetachedBrowserFrame[] = [];
public readonly parentFrame: DetachedBrowserFrame | null = null;
public readonly opener: DetachedBrowserFrame | null = null;
public readonly page: DetachedBrowserPage;
// Needs to be injected from the outside when the browser frame is constructed.
public window: IBrowserWindow;
public [PropertySymbol.asyncTaskManager] = new AsyncTaskManager();
public [PropertySymbol.exceptionObserver]: BrowserFrameExceptionObserver | null = null;
public [PropertySymbol.listeners]: { navigation: Array<() => void> } = { navigation: [] };
public [PropertySymbol.openerFrame]: IBrowserFrame | null = null;
public [PropertySymbol.openerWindow]: IBrowserWindow | ICrossOriginBrowserWindow | null = null;
public [PropertySymbol.popup] = false;

/**
* Constructor.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import VirtualConsolePrinter from '../../console/VirtualConsolePrinter.js';
import IBrowserPageViewport from '../types/IBrowserPageViewport.js';
import DetachedBrowserFrame from './DetachedBrowserFrame.js';
import DetachedBrowserContext from './DetachedBrowserContext.js';
import VirtualConsole from '../../console/VirtualConsole.js';
Expand All @@ -9,6 +8,10 @@ import IGoToOptions from '../types/IGoToOptions.js';
import IResponse from '../../fetch/types/IResponse.js';
import BrowserPageUtility from '../utilities/BrowserPageUtility.js';
import IReloadOptions from '../types/IReloadOptions.js';
import DefaultBrowserPageViewport from '../DefaultBrowserPageViewport.js';
import IOptionalBrowserPageViewport from '../types/IOptionalBrowserPageViewport.js';
import IBrowserPageViewport from '../types/IBrowserPageViewport.js';
import Event from '../../event/Event.js';

/**
* Detached browser page used when constructing a Window instance without a browser.
Expand All @@ -18,6 +21,7 @@ export default class DetachedBrowserPage implements IBrowserPage {
public readonly mainFrame: DetachedBrowserFrame;
public readonly context: DetachedBrowserContext;
public readonly console: Console;
public readonly viewport: IBrowserPageViewport = Object.assign({}, DefaultBrowserPageViewport);

/**
* Constructor.
Expand Down Expand Up @@ -126,8 +130,16 @@ export default class DetachedBrowserPage implements IBrowserPage {
*
* @param viewport Viewport.
*/
public setViewport(viewport: IBrowserPageViewport): void {
BrowserPageUtility.setViewport(this, viewport);
public setViewport(viewport: IOptionalBrowserPageViewport): void {
const previousViewport = Object.assign({}, this.viewport);
Object.assign(this.viewport, viewport);
if (
previousViewport.width !== this.viewport.width ||
previousViewport.height !== this.viewport.height ||
previousViewport.devicePixelRatio !== this.viewport.devicePixelRatio
) {
this.mainFrame.window.dispatchEvent(new Event('resize'));
}
}

/**
Expand Down
4 changes: 1 addition & 3 deletions packages/happy-dom/src/browser/types/IBrowser.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import IBrowserContext from './IBrowserContext.js';
import IBrowserFrame from './IBrowserFrame.js';
import IBrowserPage from './IBrowserPage.js';
import IBrowserSettings from './IBrowserSettings.js';

Expand Down Expand Up @@ -41,8 +40,7 @@ export default interface IBrowser {
/**
* Creates a new page.
*
* @param [opener] Opener.
* @returns Page.
*/
newPage(opener?: IBrowserFrame): IBrowserPage;
newPage(): IBrowserPage;
}
4 changes: 1 addition & 3 deletions packages/happy-dom/src/browser/types/IBrowserContext.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import ICookieContainer from '../../cookie/types/ICookieContainer.js';
import IResponseCache from '../../fetch/cache/response/IResponseCache.js';
import IBrowser from './IBrowser.js';
import IBrowserFrame from './IBrowserFrame.js';
import IBrowserPage from './IBrowserPage.js';
import IPreflightResponseCache from '../../fetch/cache/preflight/IPreflightResponseCache.js';

Expand Down Expand Up @@ -35,8 +34,7 @@ export default interface IBrowserContext {
/**
* Creates a new page.
*
* @param [opener] Opener.
* @returns Page.
*/
newPage(opener?: IBrowserFrame): IBrowserPage;
newPage(): IBrowserPage;
}
5 changes: 4 additions & 1 deletion packages/happy-dom/src/browser/types/IBrowserFrame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import IGoToOptions from './IGoToOptions.js';
import { Script } from 'vm';
import IReloadOptions from './IReloadOptions.js';
import BrowserFrameExceptionObserver from '../utilities/BrowserFrameExceptionObserver.js';
import ICrossOriginBrowserWindow from '../../window/ICrossOriginBrowserWindow.js';

/**
* Browser frame.
*/
export default interface IBrowserFrame {
readonly childFrames: IBrowserFrame[];
readonly parentFrame: IBrowserFrame | null;
readonly opener: IBrowserFrame | null;
readonly page: IBrowserPage;
readonly window: IBrowserWindow;
readonly document: IDocument;
Expand All @@ -24,6 +24,9 @@ export default interface IBrowserFrame {
[PropertySymbol.asyncTaskManager]: AsyncTaskManager;
[PropertySymbol.exceptionObserver]: BrowserFrameExceptionObserver | null;
[PropertySymbol.listeners]: { navigation: Array<() => void> };
[PropertySymbol.openerFrame]: IBrowserFrame | null;
[PropertySymbol.openerWindow]: IBrowserWindow | ICrossOriginBrowserWindow | null;
[PropertySymbol.popup]: boolean;

/**
* Returns a promise that is resolved when all resources has been loaded, fetch has completed, and all async tasks such as timers are complete.
Expand Down
6 changes: 4 additions & 2 deletions packages/happy-dom/src/browser/types/IBrowserPage.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import IBrowserPageViewport from './IBrowserPageViewport.js';
import IBrowserPageViewport from '../types/IBrowserPageViewport.js';
import VirtualConsolePrinter from '../../console/VirtualConsolePrinter.js';
import IBrowserFrame from './IBrowserFrame.js';
import IBrowserContext from './IBrowserContext.js';
import { Script } from 'vm';
import IGoToOptions from './IGoToOptions.js';
import IResponse from '../../fetch/types/IResponse.js';
import IReloadOptions from './IReloadOptions.js';
import IOptionalBrowserPageViewport from './IOptionalBrowserPageViewport.js';

/**
* Browser page.
Expand All @@ -16,6 +17,7 @@ export default interface IBrowserPage {
readonly context: IBrowserContext;
readonly console: Console;
readonly frames: IBrowserFrame[];
readonly viewport: IBrowserPageViewport;
content: string;
url: string;

Expand Down Expand Up @@ -49,7 +51,7 @@ export default interface IBrowserPage {
*
* @param viewport Viewport.
*/
setViewport(viewport: IBrowserPageViewport): void;
setViewport(viewport: IOptionalBrowserPageViewport): void;

/**
* Go to a page.
Expand Down
6 changes: 3 additions & 3 deletions packages/happy-dom/src/browser/types/IBrowserPageViewport.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export default interface IBrowserPageViewport {
width?: number;
height?: number;
devicePixelRatio?: number;
width: number;
height: number;
devicePixelRatio: number;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default interface IOptionalBrowserPageViewport {
width?: number;
height?: number;
devicePixelRatio?: number;
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ export default class BrowserFrameFactory {
frame.window[PropertySymbol.destroy]();
(<IBrowserPage | null>frame.page) = null;
(<IBrowserWindow | null>frame.window) = null;
(<IBrowserFrame | null>frame.opener) = null;
frame[PropertySymbol.openerFrame] = null;
frame[PropertySymbol.openerWindow] = null;

if (!frame.childFrames.length) {
return frame[PropertySymbol.asyncTaskManager]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import IBrowserFrame from '../types/IBrowserFrame.js';
import { URL } from 'url';
import BrowserNavigationCrossOriginPolicyEnum from '../enums/BrowserNavigationCrossOriginPolicyEnum.js';
import DetachedBrowserFrame from '../detached-browser/DetachedBrowserFrame.js';
import * as PropertySymbol from '../../PropertySymbol.js';

/**
* Browser frame validator.
Expand All @@ -18,10 +19,9 @@ export default class BrowserFrameValidator {
const settings = frame.page.context.browser.settings;
let fromURL = frame.page.mainFrame.window.location;

if (frame.opener) {
fromURL = frame.opener.window.location;
}
if (frame.parentFrame) {
if (frame[PropertySymbol.openerFrame]) {
fromURL = frame[PropertySymbol.openerFrame].window.location;
} else if (frame.parentFrame) {
fromURL = frame.parentFrame.window.location;
}

Expand Down Expand Up @@ -74,7 +74,7 @@ export default class BrowserFrameValidator {
return false;
}

if (settings.navigation.disableChildPageNavigation && !!frame.opener) {
if (settings.navigation.disableChildPageNavigation && !!frame[PropertySymbol.openerFrame]) {
return false;
}

Expand Down
Loading

0 comments on commit 8775bde

Please sign in to comment.