mirror of
				https://github.com/MontFerret/ferret.git
				synced 2025-10-30 23:37:40 +02:00 
			
		
		
		
	Added possibility to set custom viewport size (#334)
* Added possibility to set custom viewport size * Fixed linting issue * Renamed ScreenSize to Viewport * Updated e2e test
This commit is contained in:
		| @@ -3,6 +3,7 @@ import IndexPage from './pages/index.js'; | ||||
| import FormsPage from './pages/forms/index.js'; | ||||
| import EventsPage from './pages/events/index.js'; | ||||
| import IframePage from './pages/iframes/index.js'; | ||||
| import MediaPage from './pages/media/index.js'; | ||||
|  | ||||
| const e = React.createElement; | ||||
| const Router = ReactRouter.Router; | ||||
| @@ -51,6 +52,10 @@ export default React.memo(function AppComponent(params = {}) { | ||||
|                     path: '/iframe', | ||||
|                     component: IframePage | ||||
|                 }), | ||||
|                 e(Route, { | ||||
|                     path: '/media', | ||||
|                     component: MediaPage | ||||
|                 }), | ||||
|             ]), | ||||
|             redirectTo | ||||
|         ]) | ||||
|   | ||||
							
								
								
									
										26
									
								
								e2e/pages/dynamic/components/pages/media/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								e2e/pages/dynamic/components/pages/media/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| const e = React.createElement; | ||||
|  | ||||
| export default class MediaPage extends React.Component { | ||||
|     render() { | ||||
|         return e("div", { id: "media" }, [ | ||||
|             e("div", { className: "row" }, [ | ||||
|                 e("div", {className: "col-6"}, [ | ||||
|                     e("h3", null, [ | ||||
|                         "Height" | ||||
|                     ]), | ||||
|                     e("span", { id: "screen-height"}, [ | ||||
|                         window.innerHeight | ||||
|                     ]), | ||||
|                 ]), | ||||
|                 e("div", {className: "col-6"}, [ | ||||
|                     e("h3", null, [ | ||||
|                         "Width" | ||||
|                     ]), | ||||
|                     e("span", { id: "screen-width"}, [ | ||||
|                         window.innerWidth | ||||
|                     ]) | ||||
|                 ]) | ||||
|             ]) | ||||
|         ]) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										16
									
								
								e2e/tests/dynamic/doc/viewport/size.fql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								e2e/tests/dynamic/doc/viewport/size.fql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| LET url = @dynamic + "?redirect=/media" | ||||
| LET expectedW = 1920 | ||||
| LET expectedH = 1080 | ||||
|  | ||||
| LET doc = DOCUMENT(url, { | ||||
|     driver: 'cdp', | ||||
|     viewport: { | ||||
|         width: expectedW, | ||||
|         height: expectedH | ||||
|     } | ||||
| }) | ||||
|  | ||||
| LET actualW = TO_INT(INNER_TEXT(doc, '#screen-width')) | ||||
| LET actualH = TO_INT(INNER_TEXT(doc, '#screen-height')) | ||||
|  | ||||
| RETURN EXPECT(expectedW, actualW) + EXPECT(expectedH, actualH) | ||||
| @@ -20,6 +20,11 @@ const DriverName = "cdp" | ||||
| const BlankPageURL = "about:blank" | ||||
| const DefaultTimeout = 5000 * time.Millisecond | ||||
|  | ||||
| var defaultViewport = &drivers.Viewport{ | ||||
| 	Width:  1600, | ||||
| 	Height: 900, | ||||
| } | ||||
|  | ||||
| type Driver struct { | ||||
| 	mu        sync.Mutex | ||||
| 	dev       *devtool.DevTools | ||||
| @@ -42,7 +47,7 @@ func (drv *Driver) Name() string { | ||||
| 	return drv.options.Name | ||||
| } | ||||
|  | ||||
| func (drv *Driver) Open(ctx context.Context, params drivers.OpenPageParams) (drivers.HTMLPage, error) { | ||||
| func (drv *Driver) Open(ctx context.Context, params drivers.Params) (drivers.HTMLPage, error) { | ||||
| 	logger := logging.FromContext(ctx) | ||||
|  | ||||
| 	err := drv.init(ctx) | ||||
| @@ -98,6 +103,10 @@ func (drv *Driver) Open(ctx context.Context, params drivers.OpenPageParams) (dri | ||||
| 		params.UserAgent = drv.options.UserAgent | ||||
| 	} | ||||
|  | ||||
| 	if params.Viewport == nil { | ||||
| 		params.Viewport = defaultViewport | ||||
| 	} | ||||
|  | ||||
| 	return LoadHTMLPage(ctx, conn, params) | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -46,7 +46,7 @@ func handleLoadError(logger *zerolog.Logger, client *cdp.Client) { | ||||
| func LoadHTMLPage( | ||||
| 	ctx context.Context, | ||||
| 	conn *rpcc.Conn, | ||||
| 	params drivers.OpenPageParams, | ||||
| 	params drivers.Params, | ||||
| ) (*HTMLPage, error) { | ||||
| 	logger := logging.FromContext(ctx) | ||||
|  | ||||
| @@ -56,11 +56,11 @@ func LoadHTMLPage( | ||||
|  | ||||
| 	client := cdp.NewClient(conn) | ||||
|  | ||||
| 	err := runBatch( | ||||
| 		func() error { | ||||
| 			return client.Page.Enable(ctx) | ||||
| 		}, | ||||
| 	if err := client.Page.Enable(ctx); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	err := runBatch( | ||||
| 		func() error { | ||||
| 			return client.Page.SetLifecycleEventsEnabled( | ||||
| 				ctx, | ||||
| @@ -99,18 +99,50 @@ func LoadHTMLPage( | ||||
| 		func() error { | ||||
| 			return client.Network.Enable(ctx, network.NewEnableArgs()) | ||||
| 		}, | ||||
|  | ||||
| 		func() error { | ||||
| 			return client.Page.SetBypassCSP(ctx, page.NewSetBypassCSPArgs(true)) | ||||
| 		}, | ||||
|  | ||||
| 		func() error { | ||||
| 			if params.Viewport == nil { | ||||
| 				return nil | ||||
| 			} | ||||
|  | ||||
| 			orientation := emulation.ScreenOrientation{} | ||||
|  | ||||
| 			if !params.Viewport.Landscape { | ||||
| 				orientation.Type = "portraitPrimary" | ||||
| 				orientation.Angle = 0 | ||||
| 			} else { | ||||
| 				orientation.Type = "landscapePrimary" | ||||
| 				orientation.Angle = 90 | ||||
| 			} | ||||
|  | ||||
| 			scaleFactor := params.Viewport.ScaleFactor | ||||
|  | ||||
| 			if scaleFactor <= 0 { | ||||
| 				scaleFactor = 1 | ||||
| 			} | ||||
|  | ||||
| 			deviceArgs := emulation.NewSetDeviceMetricsOverrideArgs( | ||||
| 				params.Viewport.Width, | ||||
| 				params.Viewport.Height, | ||||
| 				scaleFactor, | ||||
| 				params.Viewport.Mobile, | ||||
| 			).SetScreenOrientation(orientation) | ||||
|  | ||||
| 			return client.Emulation.SetDeviceMetricsOverride( | ||||
| 				ctx, | ||||
| 				deviceArgs, | ||||
| 			) | ||||
| 		}, | ||||
| 	) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	err = client.Page.SetBypassCSP(ctx, page.NewSetBypassCSPArgs(true)) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if params.Cookies != nil { | ||||
| 		cookies := make([]network.CookieParam, 0, len(params.Cookies)) | ||||
|  | ||||
|   | ||||
| @@ -18,18 +18,10 @@ type ( | ||||
| 		drivers map[string]Driver | ||||
| 	} | ||||
|  | ||||
| 	OpenPageParams struct { | ||||
| 		URL         string | ||||
| 		UserAgent   string | ||||
| 		KeepCookies bool | ||||
| 		Cookies     []HTTPCookie | ||||
| 		Header      HTTPHeader | ||||
| 	} | ||||
|  | ||||
| 	Driver interface { | ||||
| 		io.Closer | ||||
| 		Name() string | ||||
| 		Open(ctx context.Context, params OpenPageParams) (HTMLPage, error) | ||||
| 		Open(ctx context.Context, params Params) (HTMLPage, error) | ||||
| 	} | ||||
| ) | ||||
|  | ||||
|   | ||||
| @@ -62,7 +62,7 @@ func (drv *Driver) Name() string { | ||||
| 	return DriverName | ||||
| } | ||||
|  | ||||
| func (drv *Driver) Open(ctx context.Context, params drivers.OpenPageParams) (drivers.HTMLPage, error) { | ||||
| func (drv *Driver) Open(ctx context.Context, params drivers.Params) (drivers.HTMLPage, error) { | ||||
| 	req, err := http.NewRequest(http.MethodGet, params.URL, nil) | ||||
|  | ||||
| 	if err != nil { | ||||
|   | ||||
							
								
								
									
										20
									
								
								pkg/drivers/params.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								pkg/drivers/params.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| package drivers | ||||
|  | ||||
| type ( | ||||
| 	Viewport struct { | ||||
| 		Height      int | ||||
| 		Width       int | ||||
| 		ScaleFactor float64 | ||||
| 		Mobile      bool | ||||
| 		Landscape   bool | ||||
| 	} | ||||
|  | ||||
| 	Params struct { | ||||
| 		URL         string | ||||
| 		UserAgent   string | ||||
| 		KeepCookies bool | ||||
| 		Cookies     []HTTPCookie | ||||
| 		Header      HTTPHeader | ||||
| 		Viewport    *Viewport | ||||
| 	} | ||||
| ) | ||||
| @@ -231,10 +231,10 @@ func Unmarshal(value json.RawMessage) (core.Value, error) { | ||||
| 	return Parse(o), nil | ||||
| } | ||||
|  | ||||
| func ToBoolean(input core.Value) core.Value { | ||||
| func ToBoolean(input core.Value) Boolean { | ||||
| 	switch input.Type() { | ||||
| 	case types.Boolean: | ||||
| 		return input | ||||
| 		return input.(Boolean) | ||||
| 	case types.String: | ||||
| 		return NewBoolean(input.(String) != "") | ||||
| 	case types.Int: | ||||
|   | ||||
| @@ -13,20 +13,23 @@ import ( | ||||
| ) | ||||
|  | ||||
| type PageLoadParams struct { | ||||
| 	drivers.OpenPageParams | ||||
| 	drivers.Params | ||||
| 	Driver  string | ||||
| 	Timeout time.Duration | ||||
| } | ||||
|  | ||||
| // Open opens an HTML page by a given url. | ||||
| // By default, loads a document by http call - resulted document does not support any interactions. | ||||
| // If passed "true" as a second argument, headless browser is used for loading the document which support interactions. | ||||
| // @param url (String) - Target url string. If passed "about:blank" for dynamic document - it will open an empty page. | ||||
| // @param isDynamicOrParams (Boolean|PageLoadParams) - Either a boolean value that indicates whether to use dynamic page | ||||
| // or an object with the following properties : | ||||
| // 		dynamic (Boolean) - Optional, indicates whether to use dynamic page. | ||||
| // 		timeout (Int) - Optional, Open load timeout. | ||||
| // @returns (HTMLDocument) - Returns loaded HTML document. | ||||
| // By default, loads a page by http call - resulted page does not support any interactions. | ||||
| // @param params (Object) - Optional, An object containing the following properties : | ||||
| // 		driver (String) - Optional, driver name. | ||||
| //      timeout (Int) - Optional, timeout. | ||||
| //      userAgent (String) - Optional, user agent. | ||||
| //      keepCookies (Boolean) - Optional, boolean value indicating whether to use cookies from previous sessions. | ||||
| //      	i.e. not to open a page in the Incognito mode. | ||||
| //      cookies (HTTPCookie) - Optional, set of HTTP cookies. | ||||
| //      header (HTTPHeader) - Optional, HTTP headers. | ||||
| //      viewport (Viewport) - Optional, viewport params. | ||||
| // @returns (HTMLPage) - Returns loaded HTML page. | ||||
| func Open(ctx context.Context, args ...core.Value) (core.Value, error) { | ||||
| 	err := core.ValidateArgs(args, 1, 2) | ||||
|  | ||||
| @@ -65,12 +68,12 @@ func Open(ctx context.Context, args ...core.Value) (core.Value, error) { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	return drv.Open(ctx, params.OpenPageParams) | ||||
| 	return drv.Open(ctx, params.Params) | ||||
| } | ||||
|  | ||||
| func newDefaultDocLoadParams(url values.String) PageLoadParams { | ||||
| 	return PageLoadParams{ | ||||
| 		OpenPageParams: drivers.OpenPageParams{ | ||||
| 		Params: drivers.Params{ | ||||
| 			URL: url.String(), | ||||
| 		}, | ||||
| 		Timeout: time.Second * 30, | ||||
| @@ -155,9 +158,19 @@ func newPageLoadParams(url values.String, arg core.Value) (PageLoadParams, error | ||||
| 			res.Header = header | ||||
| 		} | ||||
|  | ||||
| 		viewport, exists := obj.Get(values.NewString("viewport")) | ||||
|  | ||||
| 		if exists { | ||||
| 			viewport, err := parseViewport(viewport) | ||||
|  | ||||
| 			if err != nil { | ||||
| 				return res, err | ||||
| 			} | ||||
|  | ||||
| 			res.Viewport = viewport | ||||
| 		} | ||||
| 	case types.String: | ||||
| 		res.Driver = arg.(values.String).String() | ||||
|  | ||||
| 	case types.Boolean: | ||||
| 		b := arg.(values.Boolean) | ||||
|  | ||||
| @@ -165,7 +178,6 @@ func newPageLoadParams(url values.String, arg core.Value) (PageLoadParams, error | ||||
| 		if b { | ||||
| 			res.Driver = cdp.DriverName | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	return res, nil | ||||
| @@ -291,3 +303,53 @@ func parseHeader(header *values.Object) drivers.HTTPHeader { | ||||
|  | ||||
| 	return res | ||||
| } | ||||
|  | ||||
| func parseViewport(value core.Value) (*drivers.Viewport, error) { | ||||
| 	if err := core.ValidateType(value, types.Object); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	res := &drivers.Viewport{} | ||||
|  | ||||
| 	viewport := value.(*values.Object) | ||||
|  | ||||
| 	width, exists := viewport.Get(values.NewString("width")) | ||||
|  | ||||
| 	if exists { | ||||
| 		if err := core.ValidateType(width, types.Int); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		res.Width = int(values.ToInt(width)) | ||||
| 	} | ||||
|  | ||||
| 	height, exists := viewport.Get(values.NewString("height")) | ||||
|  | ||||
| 	if exists { | ||||
| 		if err := core.ValidateType(height, types.Int); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		res.Height = int(values.ToInt(height)) | ||||
| 	} | ||||
|  | ||||
| 	mobile, exists := viewport.Get(values.NewString("mobile")) | ||||
|  | ||||
| 	if exists { | ||||
| 		res.Mobile = bool(values.ToBoolean(mobile)) | ||||
| 	} | ||||
|  | ||||
| 	landscape, exists := viewport.Get(values.NewString("landscape")) | ||||
|  | ||||
| 	if exists { | ||||
| 		res.Landscape = bool(values.ToBoolean(landscape)) | ||||
| 	} | ||||
|  | ||||
| 	scaleFactor, exists := viewport.Get(values.NewString("scaleFactor")) | ||||
|  | ||||
| 	if exists { | ||||
| 		res.ScaleFactor = float64(values.ToFloat(scaleFactor)) | ||||
| 	} | ||||
|  | ||||
| 	return res, nil | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user