๐Ÿก index : quine-global/webdriverio.git

import { sleep } from '@wdio/utils'

import newWindowHelper from '../../scripts/newWindow.js'
import { getContextManager } from '../../session/context.js'
import type { NewWindowOptions } from '../../types.js'
import logger from '@wdio/logger'
const log = logger('webdriverio:newWindow')

const WAIT_FOR_NEW_HANDLE_TIMEOUT = 3000

/**
 *
 * Open new window or tab in browser (defaults to a new window if not specified).
 * This command is the equivalent function to `window.open()`. This command does not work in mobile environments.
 *
 * __Note:__ When calling this command you automatically switch to the new window or tab.
 *
 * <example>
    :newWindowSync.js
    it('should open a new window', async () => {
        await browser.url('https://google.com')
        console.log(await browser.getTitle()) // outputs: "Google"

        const result = await browser.newWindow('https://webdriver.io', {
            windowName: 'WebdriverIO window',
            windowFeature: 'width=420,height=230,resizable,scrollbars=yes,status=1',
        })
        console.log(await browser.getTitle()) // outputs: "WebdriverIO ยท Next-gen browser and mobile automation test framework for Node.js"
        console.log(result.type) // outputs: "window"
        const handles = await browser.getWindowHandles()
        await browser.switchToWindow(handles[1])
        await browser.closeWindow()
        await browser.switchToWindow(handles[0])
        console.log(await browser.getTitle()) // outputs: "Google"
    });
 * </example>
 * <example>
      :newTabSync.js
      it('should open a new tab', async () => {
          await browser.url('https://google.com')
          console.log(await browser.getTitle()) // outputs: "Google"

          await browser.newWindow('https://webdriver.io', {
              type:'tab',
              windowName: 'WebdriverIO window',
              windowFeature: 'width=420,height=230,resizable,scrollbars=yes,status=1',
          })
          console.log(await browser.getTitle()) // outputs: "WebdriverIO ยท Next-gen browser and mobile automation test framework for Node.js"
          console.log(result.type) // outputs: "tab"
          const handles = await browser.getWindowHandles()
          await browser.switchToWindow(handles[1])
          await browser.closeWindow()
          await browser.switchToWindow(handles[0])
          console.log(await browser.getTitle()) // outputs: "Google"
     });
 * </example>
 *
 * @param {string}  url      website URL to open
 * @param {NewWindowOptions=} options                newWindow command options
 * @param {string=}           options.type           type of new window: 'tab' or 'window'
 * @param {String=}           options.windowName     name of the new window
 * @param {String=}           options.windowFeatures features of opened window (e.g. size, position, scrollbars, etc.)
 *
 * @return {Object}          An object containing the window handle and the type of new window `{handle: string, type: string}` handle - The ID of the window handle of the new tab or window, type - The type of the new window, either 'tab' or 'window'
 *
 * @throws {Error} If `url` is invalid, if the command is used on mobile, or `type` is not 'tab' or 'window'.
 *
 * @uses browser/execute, protocol/getWindowHandles, protocol/switchToWindow
 * @alias browser.newWindow
 * @type window or tab
 */
export async function newWindow (
    this: WebdriverIO.Browser,
    url: string,
    { type = 'window', windowName = '', windowFeatures = '' }: NewWindowOptions = {}
): Promise<{ handle: string, type: 'tab' | 'window' }> {
    /**
     * parameter check
     */
    if (typeof url !== 'string') {
        throw new Error('number or type of arguments don\'t agree with newWindow command')
    }

    /**
    * Validate the 'type' parameter to ensure it is either 'tab' or 'window'
    */
    if (!['tab', 'window'].includes(type)) {
        throw new Error(`Invalid type '${type}' provided to newWindow command. Use either 'tab' or 'window'`)
    }

    if (windowName || windowFeatures) {
        log.warn('The "windowName" and "windowFeatures" options are deprecated and only supported in WebDriver Classic sessions.')
    }

    /**
     * mobile check
     */
    if (this.isMobile) {
        throw new Error('newWindow command is not supported on mobile platforms')
    }

    const tabsBefore = await this.getWindowHandles()

    if (this.isBidi) {
        const contextManager = getContextManager(this)
        const { context } = await this.browsingContextCreate({ type })
        contextManager.setCurrentContext(context)
        await this.browsingContextNavigate({ context, url })
    } else {
        await this.execute(newWindowHelper, url, windowName, windowFeatures)
    }

    /**
     * if tests are run in DevTools there might be a delay until
     * a new window handle got registered, this little procedure
     * waits for it to exist and avoid race conditions
     */
    let tabsAfter = await this.getWindowHandles()
    const now = Date.now()
    while ((Date.now() - now) < WAIT_FOR_NEW_HANDLE_TIMEOUT) {
        tabsAfter = await this.getWindowHandles()
        if (tabsAfter.length > tabsBefore.length) {
            break
        }
        await sleep(100)
    }
    const newTab = tabsAfter.pop()

    if (!newTab) {
        throw new Error('No window handle was found to switch to')
    }

    await this.switchToWindow(newTab)
    return { handle: newTab, type }
}