feat: add will-frame-navigate event (#34418)
		
	* feat: add will-navigate-in-frame event to webContents * docs: add documentation for webview will-frame-navigate event * feat: Eliminate isInPlace argument from will-frame-navigate event * fix: Fire will-frame-navigate before will-navigate * feat: send will-frame-navigate with a WebFrameMain in the event details * docs: Update WebContents docs for new API signature * feat: Add custom event forwarding for <webview> will-frame-navigate * fix: wrap WebFrameMain so it can be sent as an event * test: update webContents and <webview> tests to match new signatures * chore: undo unnecessary change * fix: don't switch will-navigate to use EmitNavigationEventDetails * test: clean up will-navigate and will-frame-navigate tests for <webview> * chore: apply lint fixes * chore: move GetRenderFrameHost helper into anonymous namespace * docs: auto-generate WillFrameNavigateDetails rather than defining it manually * test: Update <webview> tests to actually pass under new spec runner * docs: Add section explaining relationship between various nav events * test: Add some tests to ensure navigation event order doesn't silently change * test: Always monitor all nav events to ensure unexpected ones don't fire * test: Add test to verify in-page navigation event order * feat: Change to new style where extra params are exposed as event props * fix: Remove unused EmitNavigationEventDetails * fix: Update tests to use new async helpers * docs: Rename and reorder sections documenting navigation events --------- Co-authored-by: Milan Burda <milan.burda@gmail.com>
This commit is contained in:
		
					parent
					
						
							
								2e1f803f37
							
						
					
				
			
			
				commit
				
					
						2b9dae4b06
					
				
			
		
					 8 changed files with 540 additions and 14 deletions
				
			
		| 
						 | 
					@ -19,6 +19,36 @@ const contents = win.webContents
 | 
				
			||||||
console.log(contents)
 | 
					console.log(contents)
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Navigation Events
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Several events can be used to monitor navigations as they occur within a `webContents`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Document Navigations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When a `webContents` navigates to another page (as opposed to an [in-page navigation](web-contents.md#in-page-navigation)), the following events will be fired.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* [`did-start-navigation`](web-contents.md#event-did-start-navigation)
 | 
				
			||||||
 | 
					* [`will-frame-navigate`](web-contents.md#event-will-frame-navigate)
 | 
				
			||||||
 | 
					* [`will-navigate`](web-contents.md#event-will-navigate) (only fired when main frame navigates)
 | 
				
			||||||
 | 
					* [`will-redirect`](web-contents.md#event-will-redirect) (only fired when a redirect happens during navigation)
 | 
				
			||||||
 | 
					* [`did-redirect-navigation`](web-contents.md#event-did-redirect-navigation) (only fired when a redirect happens during navigation)
 | 
				
			||||||
 | 
					* [`did-frame-navigate`](web-contents.md#event-did-frame-navigate)
 | 
				
			||||||
 | 
					* [`did-navigate`](web-contents.md#event-did-navigate) (only fired when main frame navigates)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Subsequent events will not fire if `event.preventDefault()` is called on any of the cancellable events.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### In-page Navigation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In-page navigations don't cause the page to reload, but instead navigate to a location within the current page. These events are not cancellable. For an in-page navigations, the following events will fire in this order:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* [`did-start-navigation`](web-contents.md#event-did-start-navigation)
 | 
				
			||||||
 | 
					* [`did-navigate-in-page`](web-contents.md#event-did-navigate-in-page)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Frame Navigation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The [`will-navigate`](web-contents.md#event-will-navigate) and [`did-navigate`](web-contents.md#event-did-navigate) events only fire when the [mainFrame](web-contents.md#contentsmainframe-readonly) navigates.
 | 
				
			||||||
 | 
					If you want to also observe navigations in `<iframe>`s, use [`will-frame-navigate`](web-contents.md#event-will-frame-navigate) and [`did-frame-navigate`](web-contents.md#event-did-frame-navigate) events.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Methods
 | 
					## Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
These methods can be accessed from the `webContents` module:
 | 
					These methods can be accessed from the `webContents` module:
 | 
				
			||||||
| 
						 | 
					@ -225,7 +255,7 @@ Returns:
 | 
				
			||||||
* `frameProcessId` Integer _Deprecated_
 | 
					* `frameProcessId` Integer _Deprecated_
 | 
				
			||||||
* `frameRoutingId` Integer _Deprecated_
 | 
					* `frameRoutingId` Integer _Deprecated_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Emitted when a user or the page wants to start navigation. It can happen when
 | 
					Emitted when a user or the page wants to start navigation on the main frame. It can happen when
 | 
				
			||||||
the `window.location` object is changed or a user clicks a link in the page.
 | 
					the `window.location` object is changed or a user clicks a link in the page.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This event will not emit when the navigation is started programmatically with
 | 
					This event will not emit when the navigation is started programmatically with
 | 
				
			||||||
| 
						 | 
					@ -237,6 +267,34 @@ this purpose.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Calling `event.preventDefault()` will prevent the navigation.
 | 
					Calling `event.preventDefault()` will prevent the navigation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Event: 'will-frame-navigate'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Returns:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `details` Event<>
 | 
				
			||||||
 | 
					  * `url` string - The URL the frame is navigating to.
 | 
				
			||||||
 | 
					  * `isMainFrame` boolean - True if the navigation is taking place in a main frame.
 | 
				
			||||||
 | 
					  * `frame` WebFrameMain - The frame to be navigated.
 | 
				
			||||||
 | 
					  * `initiator` WebFrameMain (optional) - The frame which initiated the
 | 
				
			||||||
 | 
					    navigation, which can be a parent frame (e.g. via `window.open` with a
 | 
				
			||||||
 | 
					    frame's name), or null if the navigation was not initiated by a frame. This
 | 
				
			||||||
 | 
					    can also be null if the initiating frame was deleted before the event was
 | 
				
			||||||
 | 
					    emitted.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Emitted when a user or the page wants to start navigation in any frame. It can happen when
 | 
				
			||||||
 | 
					the `window.location` object is changed or a user clicks a link in the page.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Unlike `will-navigate`, `will-frame-navigate` is fired when the main frame or any of its subframes attempts to navigate. When the navigation event comes from the main frame, `isMainFrame` will be `true`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This event will not emit when the navigation is started programmatically with
 | 
				
			||||||
 | 
					APIs like `webContents.loadURL` and `webContents.back`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It is also not emitted for in-page navigations, such as clicking anchor links
 | 
				
			||||||
 | 
					or updating the `window.location.hash`. Use `did-navigate-in-page` event for
 | 
				
			||||||
 | 
					this purpose.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Calling `event.preventDefault()` will prevent the navigation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Event: 'did-start-navigation'
 | 
					#### Event: 'did-start-navigation'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Returns:
 | 
					Returns:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -823,6 +823,28 @@ this purpose.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Calling `event.preventDefault()` does __NOT__ have any effect.
 | 
					Calling `event.preventDefault()` does __NOT__ have any effect.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Event: 'will-frame-navigate'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Returns:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `url` string
 | 
				
			||||||
 | 
					* `isMainFrame` boolean
 | 
				
			||||||
 | 
					* `frameProcessId` Integer
 | 
				
			||||||
 | 
					* `frameRoutingId` Integer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Emitted when a user or the page wants to start navigation anywhere in the `<webview>`
 | 
				
			||||||
 | 
					or any frames embedded within. It can happen when the `window.location` object is
 | 
				
			||||||
 | 
					changed or a user clicks a link in the page.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This event will not emit when the navigation is started programmatically with
 | 
				
			||||||
 | 
					APIs like `<webview>.loadURL` and `<webview>.back`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It is also not emitted during in-page navigation, such as clicking anchor links
 | 
				
			||||||
 | 
					or updating the `window.location.hash`. Use `did-navigate-in-page` event for
 | 
				
			||||||
 | 
					this purpose.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Calling `event.preventDefault()` does __NOT__ have any effect.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Event: 'did-start-navigation'
 | 
					### Event: 'did-start-navigation'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Returns:
 | 
					Returns:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -163,6 +163,16 @@ const createGuest = function (embedder: Electron.WebContents, embedderFrameId: n
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Dispatch guest's frame navigation event to embedder.
 | 
				
			||||||
 | 
					  guest.on('will-frame-navigate', function (event: Electron.WebContentsWillFrameNavigateEventParams) {
 | 
				
			||||||
 | 
					    sendToEmbedder(IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT, 'will-frame-navigate', {
 | 
				
			||||||
 | 
					      url: event.url,
 | 
				
			||||||
 | 
					      isMainFrame: event.isMainFrame,
 | 
				
			||||||
 | 
					      frameProcessId: event.frame.processId,
 | 
				
			||||||
 | 
					      frameRoutingId: event.frame.routingId
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Notify guest of embedder window visibility when it is ready
 | 
					  // Notify guest of embedder window visibility when it is ready
 | 
				
			||||||
  // FIXME Remove once https://github.com/electron/electron/issues/6828 is fixed
 | 
					  // FIXME Remove once https://github.com/electron/electron/issues/6828 is fixed
 | 
				
			||||||
  guest.on('dom-ready', function () {
 | 
					  guest.on('dom-ready', function () {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -623,6 +623,23 @@ void SetBackgroundColor(content::RenderWidgetHostView* rwhv, SkColor color) {
 | 
				
			||||||
      ->SetContentBackgroundColor(color);
 | 
					      ->SetContentBackgroundColor(color);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					content::RenderFrameHost* GetRenderFrameHost(
 | 
				
			||||||
 | 
					    content::NavigationHandle* navigation_handle) {
 | 
				
			||||||
 | 
					  int frame_tree_node_id = navigation_handle->GetFrameTreeNodeId();
 | 
				
			||||||
 | 
					  content::FrameTreeNode* frame_tree_node =
 | 
				
			||||||
 | 
					      content::FrameTreeNode::GloballyFindByID(frame_tree_node_id);
 | 
				
			||||||
 | 
					  content::RenderFrameHostManager* render_manager =
 | 
				
			||||||
 | 
					      frame_tree_node->render_manager();
 | 
				
			||||||
 | 
					  content::RenderFrameHost* frame_host = nullptr;
 | 
				
			||||||
 | 
					  if (render_manager) {
 | 
				
			||||||
 | 
					    frame_host = render_manager->speculative_frame_host();
 | 
				
			||||||
 | 
					    if (!frame_host)
 | 
				
			||||||
 | 
					      frame_host = render_manager->current_frame_host();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return frame_host;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace
 | 
					}  // namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
 | 
					#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
 | 
				
			||||||
| 
						 | 
					@ -1768,18 +1785,8 @@ bool WebContents::EmitNavigationEvent(
 | 
				
			||||||
    const std::string& event_name,
 | 
					    const std::string& event_name,
 | 
				
			||||||
    content::NavigationHandle* navigation_handle) {
 | 
					    content::NavigationHandle* navigation_handle) {
 | 
				
			||||||
  bool is_main_frame = navigation_handle->IsInMainFrame();
 | 
					  bool is_main_frame = navigation_handle->IsInMainFrame();
 | 
				
			||||||
  int frame_tree_node_id = navigation_handle->GetFrameTreeNodeId();
 | 
					 | 
				
			||||||
  content::FrameTreeNode* frame_tree_node =
 | 
					 | 
				
			||||||
      content::FrameTreeNode::GloballyFindByID(frame_tree_node_id);
 | 
					 | 
				
			||||||
  content::RenderFrameHostManager* render_manager =
 | 
					 | 
				
			||||||
      frame_tree_node->render_manager();
 | 
					 | 
				
			||||||
  content::RenderFrameHost* frame_host = nullptr;
 | 
					 | 
				
			||||||
  if (render_manager) {
 | 
					 | 
				
			||||||
    frame_host = render_manager->speculative_frame_host();
 | 
					 | 
				
			||||||
    if (!frame_host)
 | 
					 | 
				
			||||||
      frame_host = render_manager->current_frame_host();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  int frame_process_id = -1, frame_routing_id = -1;
 | 
					  int frame_process_id = -1, frame_routing_id = -1;
 | 
				
			||||||
 | 
					  content::RenderFrameHost* frame_host = GetRenderFrameHost(navigation_handle);
 | 
				
			||||||
  if (frame_host) {
 | 
					  if (frame_host) {
 | 
				
			||||||
    frame_process_id = frame_host->GetProcess()->GetID();
 | 
					    frame_process_id = frame_host->GetProcess()->GetID();
 | 
				
			||||||
    frame_routing_id = frame_host->GetRoutingID();
 | 
					    frame_routing_id = frame_host->GetRoutingID();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,6 +37,10 @@ ElectronNavigationThrottle::WillStartRequest() {
 | 
				
			||||||
    return PROCEED;
 | 
					    return PROCEED;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (handle->IsRendererInitiated() &&
 | 
				
			||||||
 | 
					      api_contents->EmitNavigationEvent("will-frame-navigate", handle)) {
 | 
				
			||||||
 | 
					    return CANCEL;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  if (handle->IsRendererInitiated() && handle->IsInMainFrame() &&
 | 
					  if (handle->IsRendererInitiated() && handle->IsInMainFrame() &&
 | 
				
			||||||
      api_contents->EmitNavigationEvent("will-navigate", handle)) {
 | 
					      api_contents->EmitNavigationEvent("will-navigate", handle)) {
 | 
				
			||||||
    return CANCEL;
 | 
					    return CANCEL;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,7 +6,7 @@ import * as qs from 'querystring';
 | 
				
			||||||
import * as http from 'http';
 | 
					import * as http from 'http';
 | 
				
			||||||
import * as os from 'os';
 | 
					import * as os from 'os';
 | 
				
			||||||
import { AddressInfo } from 'net';
 | 
					import { AddressInfo } from 'net';
 | 
				
			||||||
import { app, BrowserWindow, BrowserView, dialog, ipcMain, OnBeforeSendHeadersListenerDetails, protocol, screen, webContents, session, WebContents, WebFrameMain } from 'electron/main';
 | 
					import { app, BrowserWindow, BrowserView, dialog, ipcMain, OnBeforeSendHeadersListenerDetails, protocol, screen, webContents, webFrameMain, session, WebContents, WebFrameMain } from 'electron/main';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { emittedUntil, emittedNTimes } from './lib/events-helpers';
 | 
					import { emittedUntil, emittedNTimes } from './lib/events-helpers';
 | 
				
			||||||
import { ifit, ifdescribe, defer, listen } from './lib/spec-helpers';
 | 
					import { ifit, ifdescribe, defer, listen } from './lib/spec-helpers';
 | 
				
			||||||
| 
						 | 
					@ -568,6 +568,205 @@ describe('BrowserWindow module', () => {
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      describe('will-frame-navigate event', () => {
 | 
				
			||||||
 | 
					        let server = null as unknown as http.Server;
 | 
				
			||||||
 | 
					        let url = null as unknown as string;
 | 
				
			||||||
 | 
					        before((done) => {
 | 
				
			||||||
 | 
					          server = http.createServer((req, res) => {
 | 
				
			||||||
 | 
					            if (req.url === '/navigate-top') {
 | 
				
			||||||
 | 
					              res.end('<a target=_top href="/">navigate _top</a>');
 | 
				
			||||||
 | 
					            } else if (req.url === '/navigate-iframe') {
 | 
				
			||||||
 | 
					              res.end('<a href="/test">navigate iframe</a>');
 | 
				
			||||||
 | 
					            } else if (req.url === '/navigate-iframe?navigated') {
 | 
				
			||||||
 | 
					              res.end('Successfully navigated');
 | 
				
			||||||
 | 
					            } else if (req.url === '/navigate-iframe-immediately') {
 | 
				
			||||||
 | 
					              res.end(`
 | 
				
			||||||
 | 
					                <script type="text/javascript" charset="utf-8">
 | 
				
			||||||
 | 
					                  location.href += '?navigated'
 | 
				
			||||||
 | 
					                </script>
 | 
				
			||||||
 | 
					              `);
 | 
				
			||||||
 | 
					            } else if (req.url === '/navigate-iframe-immediately?navigated') {
 | 
				
			||||||
 | 
					              res.end('Successfully navigated');
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              res.end('');
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          server.listen(0, '127.0.0.1', () => {
 | 
				
			||||||
 | 
					            url = `http://127.0.0.1:${(server.address() as AddressInfo).port}/`;
 | 
				
			||||||
 | 
					            done();
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        after(() => {
 | 
				
			||||||
 | 
					          server.close();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it('allows the window to be closed from the event listener', (done) => {
 | 
				
			||||||
 | 
					          w.webContents.once('will-frame-navigate', () => {
 | 
				
			||||||
 | 
					            w.close();
 | 
				
			||||||
 | 
					            done();
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          w.loadFile(path.join(fixtures, 'pages', 'will-navigate.html'));
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it('can be prevented', (done) => {
 | 
				
			||||||
 | 
					          let willNavigate = false;
 | 
				
			||||||
 | 
					          w.webContents.once('will-frame-navigate', (e) => {
 | 
				
			||||||
 | 
					            willNavigate = true;
 | 
				
			||||||
 | 
					            e.preventDefault();
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          w.webContents.on('did-stop-loading', () => {
 | 
				
			||||||
 | 
					            if (willNavigate) {
 | 
				
			||||||
 | 
					              // i.e. it shouldn't have had '?navigated' appended to it.
 | 
				
			||||||
 | 
					              try {
 | 
				
			||||||
 | 
					                expect(w.webContents.getURL().endsWith('will-navigate.html')).to.be.true();
 | 
				
			||||||
 | 
					                done();
 | 
				
			||||||
 | 
					              } catch (e) {
 | 
				
			||||||
 | 
					                done(e);
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          w.loadFile(path.join(fixtures, 'pages', 'will-navigate.html'));
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it('can be prevented when navigating subframe', (done) => {
 | 
				
			||||||
 | 
					          let willNavigate = false;
 | 
				
			||||||
 | 
					          w.webContents.on('did-frame-navigate', (_event, _url, _httpResponseCode, _httpStatusText, isMainFrame, frameProcessId, frameRoutingId) => {
 | 
				
			||||||
 | 
					            if (isMainFrame) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            w.webContents.once('will-frame-navigate', (e) => {
 | 
				
			||||||
 | 
					              willNavigate = true;
 | 
				
			||||||
 | 
					              e.preventDefault();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            w.webContents.on('did-stop-loading', () => {
 | 
				
			||||||
 | 
					              const frame = webFrameMain.fromId(frameProcessId, frameRoutingId);
 | 
				
			||||||
 | 
					              expect(frame).to.not.be.undefined();
 | 
				
			||||||
 | 
					              if (willNavigate) {
 | 
				
			||||||
 | 
					                // i.e. it shouldn't have had '?navigated' appended to it.
 | 
				
			||||||
 | 
					                try {
 | 
				
			||||||
 | 
					                  expect(frame!.url.endsWith('/navigate-iframe-immediately')).to.be.true();
 | 
				
			||||||
 | 
					                  done();
 | 
				
			||||||
 | 
					                } catch (e) {
 | 
				
			||||||
 | 
					                  done(e);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          w.loadURL(`data:text/html,<iframe src="http://127.0.0.1:${(server.address() as AddressInfo).port}/navigate-iframe-immediately"></iframe>`);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it('is triggered when navigating from file: to http:', async () => {
 | 
				
			||||||
 | 
					          await w.loadFile(path.join(fixtures, 'api', 'blank.html'));
 | 
				
			||||||
 | 
					          w.webContents.executeJavaScript(`location.href = ${JSON.stringify(url)}`);
 | 
				
			||||||
 | 
					          const navigatedTo = await new Promise(resolve => {
 | 
				
			||||||
 | 
					            w.webContents.once('will-frame-navigate', (e) => {
 | 
				
			||||||
 | 
					              e.preventDefault();
 | 
				
			||||||
 | 
					              resolve(e.url);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          expect(navigatedTo).to.equal(url);
 | 
				
			||||||
 | 
					          expect(w.webContents.getURL()).to.match(/^file:/);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it('is triggered when navigating from about:blank to http:', async () => {
 | 
				
			||||||
 | 
					          await w.loadURL('about:blank');
 | 
				
			||||||
 | 
					          w.webContents.executeJavaScript(`location.href = ${JSON.stringify(url)}`);
 | 
				
			||||||
 | 
					          const navigatedTo = await new Promise(resolve => {
 | 
				
			||||||
 | 
					            w.webContents.once('will-frame-navigate', (e) => {
 | 
				
			||||||
 | 
					              e.preventDefault();
 | 
				
			||||||
 | 
					              resolve(e.url);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          expect(navigatedTo).to.equal(url);
 | 
				
			||||||
 | 
					          expect(w.webContents.getURL()).to.equal('about:blank');
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it('is triggered when a cross-origin iframe navigates _top', async () => {
 | 
				
			||||||
 | 
					          await w.loadURL(`data:text/html,<iframe src="http://127.0.0.1:${(server.address() as AddressInfo).port}/navigate-top"></iframe>`);
 | 
				
			||||||
 | 
					          await setTimeout(1000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          let willFrameNavigateEmitted = false;
 | 
				
			||||||
 | 
					          let isMainFrameValue;
 | 
				
			||||||
 | 
					          w.webContents.on('will-frame-navigate', (event) => {
 | 
				
			||||||
 | 
					            willFrameNavigateEmitted = true;
 | 
				
			||||||
 | 
					            isMainFrameValue = event.isMainFrame;
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          const didNavigatePromise = once(w.webContents, 'did-navigate');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          w.webContents.debugger.attach('1.1');
 | 
				
			||||||
 | 
					          const targets = await w.webContents.debugger.sendCommand('Target.getTargets');
 | 
				
			||||||
 | 
					          const iframeTarget = targets.targetInfos.find((t: any) => t.type === 'iframe');
 | 
				
			||||||
 | 
					          const { sessionId } = await w.webContents.debugger.sendCommand('Target.attachToTarget', {
 | 
				
			||||||
 | 
					            targetId: iframeTarget.targetId,
 | 
				
			||||||
 | 
					            flatten: true
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          await w.webContents.debugger.sendCommand('Input.dispatchMouseEvent', {
 | 
				
			||||||
 | 
					            type: 'mousePressed',
 | 
				
			||||||
 | 
					            x: 10,
 | 
				
			||||||
 | 
					            y: 10,
 | 
				
			||||||
 | 
					            clickCount: 1,
 | 
				
			||||||
 | 
					            button: 'left'
 | 
				
			||||||
 | 
					          }, sessionId);
 | 
				
			||||||
 | 
					          await w.webContents.debugger.sendCommand('Input.dispatchMouseEvent', {
 | 
				
			||||||
 | 
					            type: 'mouseReleased',
 | 
				
			||||||
 | 
					            x: 10,
 | 
				
			||||||
 | 
					            y: 10,
 | 
				
			||||||
 | 
					            clickCount: 1,
 | 
				
			||||||
 | 
					            button: 'left'
 | 
				
			||||||
 | 
					          }, sessionId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          await didNavigatePromise;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          expect(willFrameNavigateEmitted).to.be.true();
 | 
				
			||||||
 | 
					          expect(isMainFrameValue).to.be.true();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it('is triggered when a cross-origin iframe navigates itself', async () => {
 | 
				
			||||||
 | 
					          await w.loadURL(`data:text/html,<iframe src="http://127.0.0.1:${(server.address() as AddressInfo).port}/navigate-iframe"></iframe>`);
 | 
				
			||||||
 | 
					          await setTimeout(1000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          let willNavigateEmitted = false;
 | 
				
			||||||
 | 
					          let isMainFrameValue;
 | 
				
			||||||
 | 
					          w.webContents.on('will-frame-navigate', (event) => {
 | 
				
			||||||
 | 
					            willNavigateEmitted = true;
 | 
				
			||||||
 | 
					            isMainFrameValue = event.isMainFrame;
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          const didNavigatePromise = once(w.webContents, 'did-frame-navigate');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          w.webContents.debugger.attach('1.1');
 | 
				
			||||||
 | 
					          const targets = await w.webContents.debugger.sendCommand('Target.getTargets');
 | 
				
			||||||
 | 
					          const iframeTarget = targets.targetInfos.find((t: any) => t.type === 'iframe');
 | 
				
			||||||
 | 
					          const { sessionId } = await w.webContents.debugger.sendCommand('Target.attachToTarget', {
 | 
				
			||||||
 | 
					            targetId: iframeTarget.targetId,
 | 
				
			||||||
 | 
					            flatten: true
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          await w.webContents.debugger.sendCommand('Input.dispatchMouseEvent', {
 | 
				
			||||||
 | 
					            type: 'mousePressed',
 | 
				
			||||||
 | 
					            x: 10,
 | 
				
			||||||
 | 
					            y: 10,
 | 
				
			||||||
 | 
					            clickCount: 1,
 | 
				
			||||||
 | 
					            button: 'left'
 | 
				
			||||||
 | 
					          }, sessionId);
 | 
				
			||||||
 | 
					          await w.webContents.debugger.sendCommand('Input.dispatchMouseEvent', {
 | 
				
			||||||
 | 
					            type: 'mouseReleased',
 | 
				
			||||||
 | 
					            x: 10,
 | 
				
			||||||
 | 
					            y: 10,
 | 
				
			||||||
 | 
					            clickCount: 1,
 | 
				
			||||||
 | 
					            button: 'left'
 | 
				
			||||||
 | 
					          }, sessionId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          await didNavigatePromise;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          expect(willNavigateEmitted).to.be.true();
 | 
				
			||||||
 | 
					          expect(isMainFrameValue).to.be.false();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it('can cancel when a cross-origin iframe navigates itself', async () => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      describe('will-redirect event', () => {
 | 
					      describe('will-redirect event', () => {
 | 
				
			||||||
        let server: http.Server;
 | 
					        let server: http.Server;
 | 
				
			||||||
        let url: string;
 | 
					        let url: string;
 | 
				
			||||||
| 
						 | 
					@ -652,6 +851,179 @@ describe('BrowserWindow module', () => {
 | 
				
			||||||
          w.loadURL(`${url}/navigate-302`);
 | 
					          w.loadURL(`${url}/navigate-302`);
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      describe('ordering', () => {
 | 
				
			||||||
 | 
					        let server = null as unknown as http.Server;
 | 
				
			||||||
 | 
					        let url = null as unknown as string;
 | 
				
			||||||
 | 
					        const navigationEvents = [
 | 
				
			||||||
 | 
					          'did-start-navigation',
 | 
				
			||||||
 | 
					          'did-navigate-in-page',
 | 
				
			||||||
 | 
					          'will-frame-navigate',
 | 
				
			||||||
 | 
					          'will-navigate',
 | 
				
			||||||
 | 
					          'will-redirect',
 | 
				
			||||||
 | 
					          'did-redirect-navigation',
 | 
				
			||||||
 | 
					          'did-frame-navigate',
 | 
				
			||||||
 | 
					          'did-navigate'
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					        before((done) => {
 | 
				
			||||||
 | 
					          server = http.createServer((req, res) => {
 | 
				
			||||||
 | 
					            if (req.url === '/navigate') {
 | 
				
			||||||
 | 
					              res.end('<a href="/">navigate</a>');
 | 
				
			||||||
 | 
					            } else if (req.url === '/redirect') {
 | 
				
			||||||
 | 
					              res.end('<a href="/redirect2">redirect</a>');
 | 
				
			||||||
 | 
					            } else if (req.url === '/redirect2') {
 | 
				
			||||||
 | 
					              res.statusCode = 302;
 | 
				
			||||||
 | 
					              res.setHeader('location', url);
 | 
				
			||||||
 | 
					              res.end();
 | 
				
			||||||
 | 
					            } else if (req.url === '/in-page') {
 | 
				
			||||||
 | 
					              res.end('<a href="#in-page">redirect</a><div id="in-page"></div>');
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              res.end('');
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          server.listen(0, '127.0.0.1', () => {
 | 
				
			||||||
 | 
					            url = `http://127.0.0.1:${(server.address() as AddressInfo).port}/`;
 | 
				
			||||||
 | 
					            done();
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        it('for initial navigation, event order is consistent', async () => {
 | 
				
			||||||
 | 
					          const firedEvents: string[] = [];
 | 
				
			||||||
 | 
					          const expectedEventOrder = [
 | 
				
			||||||
 | 
					            'did-start-navigation',
 | 
				
			||||||
 | 
					            'did-frame-navigate',
 | 
				
			||||||
 | 
					            'did-navigate'
 | 
				
			||||||
 | 
					          ];
 | 
				
			||||||
 | 
					          const allEvents = Promise.all(navigationEvents.map(event =>
 | 
				
			||||||
 | 
					            once(w.webContents, event).then(() => firedEvents.push(event))
 | 
				
			||||||
 | 
					          ));
 | 
				
			||||||
 | 
					          const timeout = setTimeout(1000);
 | 
				
			||||||
 | 
					          w.loadURL(url);
 | 
				
			||||||
 | 
					          await Promise.race([allEvents, timeout]);
 | 
				
			||||||
 | 
					          expect(firedEvents).to.deep.equal(expectedEventOrder);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it('for second navigation, event order is consistent', async () => {
 | 
				
			||||||
 | 
					          const firedEvents: string[] = [];
 | 
				
			||||||
 | 
					          const expectedEventOrder = [
 | 
				
			||||||
 | 
					            'did-start-navigation',
 | 
				
			||||||
 | 
					            'will-frame-navigate',
 | 
				
			||||||
 | 
					            'will-navigate',
 | 
				
			||||||
 | 
					            'did-frame-navigate',
 | 
				
			||||||
 | 
					            'did-navigate'
 | 
				
			||||||
 | 
					          ];
 | 
				
			||||||
 | 
					          w.loadURL(`${url}navigate`);
 | 
				
			||||||
 | 
					          await once(w.webContents, 'did-navigate');
 | 
				
			||||||
 | 
					          await setTimeout(1000);
 | 
				
			||||||
 | 
					          navigationEvents.forEach(event =>
 | 
				
			||||||
 | 
					            once(w.webContents, event).then(() => firedEvents.push(event))
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					          const navigationFinished = once(w.webContents, 'did-navigate');
 | 
				
			||||||
 | 
					          w.webContents.debugger.attach('1.1');
 | 
				
			||||||
 | 
					          const targets = await w.webContents.debugger.sendCommand('Target.getTargets');
 | 
				
			||||||
 | 
					          const pageTarget = targets.targetInfos.find((t: any) => t.type === 'page');
 | 
				
			||||||
 | 
					          const { sessionId } = await w.webContents.debugger.sendCommand('Target.attachToTarget', {
 | 
				
			||||||
 | 
					            targetId: pageTarget.targetId,
 | 
				
			||||||
 | 
					            flatten: true
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          await w.webContents.debugger.sendCommand('Input.dispatchMouseEvent', {
 | 
				
			||||||
 | 
					            type: 'mousePressed',
 | 
				
			||||||
 | 
					            x: 10,
 | 
				
			||||||
 | 
					            y: 10,
 | 
				
			||||||
 | 
					            clickCount: 1,
 | 
				
			||||||
 | 
					            button: 'left'
 | 
				
			||||||
 | 
					          }, sessionId);
 | 
				
			||||||
 | 
					          await w.webContents.debugger.sendCommand('Input.dispatchMouseEvent', {
 | 
				
			||||||
 | 
					            type: 'mouseReleased',
 | 
				
			||||||
 | 
					            x: 10,
 | 
				
			||||||
 | 
					            y: 10,
 | 
				
			||||||
 | 
					            clickCount: 1,
 | 
				
			||||||
 | 
					            button: 'left'
 | 
				
			||||||
 | 
					          }, sessionId);
 | 
				
			||||||
 | 
					          await navigationFinished;
 | 
				
			||||||
 | 
					          expect(firedEvents).to.deep.equal(expectedEventOrder);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it('when navigating with redirection, event order is consistent', async () => {
 | 
				
			||||||
 | 
					          const firedEvents: string[] = [];
 | 
				
			||||||
 | 
					          const expectedEventOrder = [
 | 
				
			||||||
 | 
					            'did-start-navigation',
 | 
				
			||||||
 | 
					            'will-frame-navigate',
 | 
				
			||||||
 | 
					            'will-navigate',
 | 
				
			||||||
 | 
					            'will-redirect',
 | 
				
			||||||
 | 
					            'did-redirect-navigation',
 | 
				
			||||||
 | 
					            'did-frame-navigate',
 | 
				
			||||||
 | 
					            'did-navigate'
 | 
				
			||||||
 | 
					          ];
 | 
				
			||||||
 | 
					          w.loadURL(`${url}redirect`);
 | 
				
			||||||
 | 
					          await once(w.webContents, 'did-navigate');
 | 
				
			||||||
 | 
					          await setTimeout(1000);
 | 
				
			||||||
 | 
					          navigationEvents.forEach(event =>
 | 
				
			||||||
 | 
					            once(w.webContents, event).then(() => firedEvents.push(event))
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					          const navigationFinished = once(w.webContents, 'did-navigate');
 | 
				
			||||||
 | 
					          w.webContents.debugger.attach('1.1');
 | 
				
			||||||
 | 
					          const targets = await w.webContents.debugger.sendCommand('Target.getTargets');
 | 
				
			||||||
 | 
					          const pageTarget = targets.targetInfos.find((t: any) => t.type === 'page');
 | 
				
			||||||
 | 
					          const { sessionId } = await w.webContents.debugger.sendCommand('Target.attachToTarget', {
 | 
				
			||||||
 | 
					            targetId: pageTarget.targetId,
 | 
				
			||||||
 | 
					            flatten: true
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          await w.webContents.debugger.sendCommand('Input.dispatchMouseEvent', {
 | 
				
			||||||
 | 
					            type: 'mousePressed',
 | 
				
			||||||
 | 
					            x: 10,
 | 
				
			||||||
 | 
					            y: 10,
 | 
				
			||||||
 | 
					            clickCount: 1,
 | 
				
			||||||
 | 
					            button: 'left'
 | 
				
			||||||
 | 
					          }, sessionId);
 | 
				
			||||||
 | 
					          await w.webContents.debugger.sendCommand('Input.dispatchMouseEvent', {
 | 
				
			||||||
 | 
					            type: 'mouseReleased',
 | 
				
			||||||
 | 
					            x: 10,
 | 
				
			||||||
 | 
					            y: 10,
 | 
				
			||||||
 | 
					            clickCount: 1,
 | 
				
			||||||
 | 
					            button: 'left'
 | 
				
			||||||
 | 
					          }, sessionId);
 | 
				
			||||||
 | 
					          await navigationFinished;
 | 
				
			||||||
 | 
					          expect(firedEvents).to.deep.equal(expectedEventOrder);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it('when navigating in-page, event order is consistent', async () => {
 | 
				
			||||||
 | 
					          const firedEvents: string[] = [];
 | 
				
			||||||
 | 
					          const expectedEventOrder = [
 | 
				
			||||||
 | 
					            'did-start-navigation',
 | 
				
			||||||
 | 
					            'did-navigate-in-page'
 | 
				
			||||||
 | 
					          ];
 | 
				
			||||||
 | 
					          w.loadURL(`${url}in-page`);
 | 
				
			||||||
 | 
					          await once(w.webContents, 'did-navigate');
 | 
				
			||||||
 | 
					          await setTimeout(1000);
 | 
				
			||||||
 | 
					          navigationEvents.forEach(event =>
 | 
				
			||||||
 | 
					            once(w.webContents, event).then(() => firedEvents.push(event))
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					          const navigationFinished = once(w.webContents, 'did-navigate-in-page');
 | 
				
			||||||
 | 
					          w.webContents.debugger.attach('1.1');
 | 
				
			||||||
 | 
					          const targets = await w.webContents.debugger.sendCommand('Target.getTargets');
 | 
				
			||||||
 | 
					          const pageTarget = targets.targetInfos.find((t: any) => t.type === 'page');
 | 
				
			||||||
 | 
					          const { sessionId } = await w.webContents.debugger.sendCommand('Target.attachToTarget', {
 | 
				
			||||||
 | 
					            targetId: pageTarget.targetId,
 | 
				
			||||||
 | 
					            flatten: true
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          await w.webContents.debugger.sendCommand('Input.dispatchMouseEvent', {
 | 
				
			||||||
 | 
					            type: 'mousePressed',
 | 
				
			||||||
 | 
					            x: 10,
 | 
				
			||||||
 | 
					            y: 10,
 | 
				
			||||||
 | 
					            clickCount: 1,
 | 
				
			||||||
 | 
					            button: 'left'
 | 
				
			||||||
 | 
					          }, sessionId);
 | 
				
			||||||
 | 
					          await w.webContents.debugger.sendCommand('Input.dispatchMouseEvent', {
 | 
				
			||||||
 | 
					            type: 'mouseReleased',
 | 
				
			||||||
 | 
					            x: 10,
 | 
				
			||||||
 | 
					            y: 10,
 | 
				
			||||||
 | 
					            clickCount: 1,
 | 
				
			||||||
 | 
					            button: 'left'
 | 
				
			||||||
 | 
					          }, sessionId);
 | 
				
			||||||
 | 
					          await navigationFinished;
 | 
				
			||||||
 | 
					          expect(firedEvents).to.deep.equal(expectedEventOrder);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										12
									
								
								spec/fixtures/pages/webview-will-navigate-in-frame.html
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								spec/fixtures/pages/webview-will-navigate-in-frame.html
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					<html>
 | 
				
			||||||
 | 
					<body>
 | 
				
			||||||
 | 
					  <script>
 | 
				
			||||||
 | 
					    function loadSubframe() {
 | 
				
			||||||
 | 
					      const frame = document.createElement("iframe");
 | 
				
			||||||
 | 
					      frame.id = "frame";
 | 
				
			||||||
 | 
					      frame.setAttribute("src", "./webview-will-navigate.html");
 | 
				
			||||||
 | 
					      document.body.appendChild(frame);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  </script>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
| 
						 | 
					@ -1480,7 +1480,7 @@ describe('<webview> tag', function () {
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    describe('will-navigate event', () => {
 | 
					    describe('will-navigate event', () => {
 | 
				
			||||||
      it('emits when a url that leads to outside of the page is clicked', async () => {
 | 
					      it('emits when a url that leads to outside of the page is loaded', async () => {
 | 
				
			||||||
        const { url } = await loadWebViewAndWaitForEvent(w, {
 | 
					        const { url } = await loadWebViewAndWaitForEvent(w, {
 | 
				
			||||||
          src: `file://${fixtures}/pages/webview-will-navigate.html`
 | 
					          src: `file://${fixtures}/pages/webview-will-navigate.html`
 | 
				
			||||||
        }, 'will-navigate');
 | 
					        }, 'will-navigate');
 | 
				
			||||||
| 
						 | 
					@ -1489,6 +1489,47 @@ describe('<webview> tag', function () {
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    describe('will-frame-navigate event', () => {
 | 
				
			||||||
 | 
					      it('emits when a link that leads to outside of the page is loaded', async () => {
 | 
				
			||||||
 | 
					        const { url, isMainFrame } = await loadWebViewAndWaitForEvent(w, {
 | 
				
			||||||
 | 
					          src: `file://${fixtures}/pages/webview-will-navigate.html`
 | 
				
			||||||
 | 
					        }, 'will-frame-navigate');
 | 
				
			||||||
 | 
					        expect(url).to.equal('http://host/');
 | 
				
			||||||
 | 
					        expect(isMainFrame).to.be.true();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      it('emits when a link within an iframe, which leads to outside of the page, is loaded', async () => {
 | 
				
			||||||
 | 
					        await loadWebView(w, {
 | 
				
			||||||
 | 
					          src: `file://${fixtures}/pages/webview-will-navigate-in-frame.html`,
 | 
				
			||||||
 | 
					          nodeIntegration: ''
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const { url, frameProcessId, frameRoutingId } = await w.executeJavaScript(`
 | 
				
			||||||
 | 
					          new Promise((resolve, reject) => {
 | 
				
			||||||
 | 
					            let hasFrameNavigatedOnce = false;
 | 
				
			||||||
 | 
					            const webview = document.getElementById('webview');
 | 
				
			||||||
 | 
					            webview.addEventListener('will-frame-navigate', ({url, isMainFrame, frameProcessId, frameRoutingId}) => {
 | 
				
			||||||
 | 
					              if (isMainFrame) return;
 | 
				
			||||||
 | 
					              if (hasFrameNavigatedOnce) resolve({
 | 
				
			||||||
 | 
					                url,
 | 
				
			||||||
 | 
					                isMainFrame,
 | 
				
			||||||
 | 
					                frameProcessId,
 | 
				
			||||||
 | 
					                frameRoutingId,
 | 
				
			||||||
 | 
					              });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              // First navigation is the initial iframe load within the <webview>
 | 
				
			||||||
 | 
					              hasFrameNavigatedOnce = true;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            webview.executeJavaScript('loadSubframe()');
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        `);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        expect(url).to.equal('http://host/');
 | 
				
			||||||
 | 
					        expect(frameProcessId).to.be.a('number');
 | 
				
			||||||
 | 
					        expect(frameRoutingId).to.be.a('number');
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    describe('did-navigate event', () => {
 | 
					    describe('did-navigate event', () => {
 | 
				
			||||||
      it('emits when a url that leads to outside of the page is clicked', async () => {
 | 
					      it('emits when a url that leads to outside of the page is clicked', async () => {
 | 
				
			||||||
        const pageUrl = url.pathToFileURL(path.join(fixtures, 'pages', 'webview-will-navigate.html')).toString();
 | 
					        const pageUrl = url.pathToFileURL(path.join(fixtures, 'pages', 'webview-will-navigate.html')).toString();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue