Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 40 additions & 17 deletions lib/helper/Playwright.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import {
clearString,
requireWithFallback,
normalizeSpacesInString,
normalizePath,
resolveUrl,
relativeDir,
} from '../utils.js'
import { isColorProperty, convertColorToRGBA } from '../colorUtils.js'
Expand Down Expand Up @@ -2412,7 +2414,7 @@ class Playwright extends Helper {
const currentUrl = await this._getPageUrl()
const baseUrl = this.options.url || 'http://localhost'
const actualPath = new URL(currentUrl, baseUrl).pathname
return equals('url path').assert(path, actualPath)
return equals('url path').assert(normalizePath(path), normalizePath(actualPath))
}

/**
Expand All @@ -2422,7 +2424,7 @@ class Playwright extends Helper {
const currentUrl = await this._getPageUrl()
const baseUrl = this.options.url || 'http://localhost'
const actualPath = new URL(currentUrl, baseUrl).pathname
return equals('url path').negate(path, actualPath)
return equals('url path').negate(normalizePath(path), normalizePath(actualPath))
}

/**
Expand Down Expand Up @@ -3382,20 +3384,21 @@ class Playwright extends Helper {
*/
async waitInUrl(urlPart, sec = null) {
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
const expectedUrl = resolveUrl(urlPart, this.options.url)

return this.page
.waitForFunction(
urlPart => {
const currUrl = decodeURIComponent(decodeURIComponent(decodeURIComponent(window.location.href)))
return currUrl.indexOf(urlPart) > -1
},
urlPart,
expectedUrl,
{ timeout: waitTimeout },
)
.catch(async e => {
const currUrl = await this._getPageUrl() // Required because the waitForFunction can't return data.
const currUrl = await this._getPageUrl()
if (/Timeout/i.test(e.message)) {
throw new Error(`expected url to include ${urlPart}, but found ${currUrl}`)
throw new Error(`expected url to include ${expectedUrl}, but found ${currUrl}`)
} else {
throw e
}
Expand All @@ -3407,26 +3410,46 @@ class Playwright extends Helper {
*/
async waitUrlEquals(urlPart, sec = null) {
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout

const baseUrl = this.options.url
let expectedUrl = urlPart
if (urlPart.indexOf('http') < 0) {
expectedUrl = baseUrl + urlPart
}
const expectedUrl = resolveUrl(urlPart, this.options.url)

try {
await this.page.waitForURL(
url => url.href.includes(expectedUrl),
url => url.href === expectedUrl,
{ timeout: waitTimeout },
)
} catch (e) {
const currUrl = await this._getPageUrl()
if (/Timeout/i.test(e.message)) {
if (!currUrl.includes(expectedUrl)) {
throw new Error(`expected url to be ${expectedUrl}, but found ${currUrl}`)
} else {
throw new Error(`expected url not loaded, error message: ${e.message}`)
}
throw new Error(`expected url to be ${expectedUrl}, but found ${currUrl}`)
} else {
throw e
}
}
}

/**
* {{> waitCurrentPathEquals }}
*/
async waitCurrentPathEquals(path, sec = null) {
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
const normalizedPath = normalizePath(path)

try {
await this.page.waitForFunction(
expectedPath => {
const actualPath = window.location.pathname
const normalizePath = p => (p === '' || p === '/' ? '/' : p.replace(/\/+/g, '/').replace(/\/$/, '') || '/')
return normalizePath(actualPath) === expectedPath
},
{ timeout: waitTimeout },
normalizedPath,
)
} catch (e) {
const currentUrl = await this._getPageUrl()
const baseUrl = this.options.url || 'http://localhost'
const actualPath = new URL(currentUrl, baseUrl).pathname
if (/Timeout/i.test(e.message)) {
throw new Error(`expected path to be ${normalizedPath}, but found ${normalizePath(actualPath)}`)
} else {
throw e
}
Expand Down
57 changes: 40 additions & 17 deletions lib/helper/Puppeteer.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import {
isModifierKey,
requireWithFallback,
normalizeSpacesInString,
normalizePath,
resolveUrl,
} from '../utils.js'
import { isColorProperty, convertColorToRGBA } from '../colorUtils.js'
import ElementNotFound from './errors/ElementNotFound.js'
Expand Down Expand Up @@ -1691,7 +1693,7 @@ class Puppeteer extends Helper {
const currentUrl = await this._getPageUrl()
const baseUrl = this.options.url || 'http://localhost'
const actualPath = new URL(currentUrl, baseUrl).pathname
return equals('url path').assert(path, actualPath)
return equals('url path').assert(normalizePath(path), normalizePath(actualPath))
}

/**
Expand All @@ -1701,7 +1703,7 @@ class Puppeteer extends Helper {
const currentUrl = await this._getPageUrl()
const baseUrl = this.options.url || 'http://localhost'
const actualPath = new URL(currentUrl, baseUrl).pathname
return equals('url path').negate(path, actualPath)
return equals('url path').negate(normalizePath(path), normalizePath(actualPath))
}

/**
Expand Down Expand Up @@ -2441,6 +2443,7 @@ class Puppeteer extends Helper {
*/
async waitInUrl(urlPart, sec = null) {
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
const expectedUrl = resolveUrl(urlPart, this.options.url)

return this.page
.waitForFunction(
Expand All @@ -2449,12 +2452,12 @@ class Puppeteer extends Helper {
return currUrl.indexOf(urlPart) > -1
},
{ timeout: waitTimeout },
urlPart,
expectedUrl,
)
.catch(async e => {
const currUrl = await this._getPageUrl() // Required because the waitForFunction can't return data.
const currUrl = await this._getPageUrl()
if (/Waiting failed:/i.test(e.message) || /failed: timeout/i.test(e.message)) {
throw new Error(`expected url to include ${urlPart}, but found ${currUrl}`)
throw new Error(`expected url to include ${expectedUrl}, but found ${currUrl}`)
} else {
throw e
}
Expand All @@ -2466,30 +2469,50 @@ class Puppeteer extends Helper {
*/
async waitUrlEquals(urlPart, sec = null) {
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout

const baseUrl = this.options.url
let expectedUrl = urlPart
if (urlPart.indexOf('http') < 0) {
expectedUrl = baseUrl + urlPart
}
const expectedUrl = resolveUrl(urlPart, this.options.url)

return this.page
.waitForFunction(
url => {
const currUrl = decodeURIComponent(window.location.href)
return currUrl.indexOf(url) > -1
return currUrl === url
},
{ timeout: waitTimeout },
expectedUrl,
)
.catch(async e => {
const currUrl = await this._getPageUrl()
if (/Waiting failed/i.test(e.message) || /failed: timeout/i.test(e.message)) {
if (!currUrl.includes(expectedUrl)) {
throw new Error(`expected url to be ${expectedUrl}, but found ${currUrl}`)
} else {
throw new Error(`expected url not loaded, error message: ${e.message}`)
}
throw new Error(`expected url to be ${expectedUrl}, but found ${currUrl}`)
} else {
throw e
}
})
}

/**
* {{> waitCurrentPathEquals }}
*/
async waitCurrentPathEquals(path, sec = null) {
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
const normalizedPath = normalizePath(path)

return this.page
.waitForFunction(
expectedPath => {
const actualPath = window.location.pathname
const normalizePath = p => (p === '' || p === '/' ? '/' : p.replace(/\/+/g, '/').replace(/\/$/, '') || '/')
return normalizePath(actualPath) === expectedPath
},
{ timeout: waitTimeout },
normalizedPath,
)
.catch(async e => {
const currUrl = await this._getPageUrl()
const baseUrl = this.options.url || 'http://localhost'
const actualPath = new URL(currUrl, baseUrl).pathname
if (/Waiting failed/i.test(e.message) || /failed: timeout/i.test(e.message)) {
throw new Error(`expected path to be ${normalizedPath}, but found ${normalizePath(actualPath)}`)
} else {
throw e
}
Expand Down
59 changes: 48 additions & 11 deletions lib/helper/WebDriver.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,18 @@ import output from '../output.js'
const { debug } = output
import { empty } from '../assert/empty.js'
import { truth } from '../assert/truth.js'
import { xpathLocator, fileExists, decodeUrl, chunkArray, convertCssPropertiesToCamelCase, screenshotOutputFolder, getNormalizedKeyAttributeValue, modifierKeys } from '../utils.js'
import {
xpathLocator,
fileExists,
decodeUrl,
chunkArray,
convertCssPropertiesToCamelCase,
screenshotOutputFolder,
getNormalizedKeyAttributeValue,
modifierKeys,
normalizePath,
resolveUrl,
} from '../utils.js'
import { isColorProperty, convertColorToRGBA } from '../colorUtils.js'
import ElementNotFound from './errors/ElementNotFound.js'
import ConnectionRefused from './errors/ConnectionRefused.js'
Expand Down Expand Up @@ -1851,7 +1862,7 @@ class WebDriver extends Helper {
const currentUrl = await this.browser.getUrl()
const baseUrl = this.options.url || 'http://localhost'
const actualPath = new URL(currentUrl, baseUrl).pathname
return equals('url path').assert(path, actualPath)
return equals('url path').assert(normalizePath(path), normalizePath(actualPath))
}

/**
Expand All @@ -1861,7 +1872,7 @@ class WebDriver extends Helper {
const currentUrl = await this.browser.getUrl()
const baseUrl = this.options.url || 'http://localhost'
const actualPath = new URL(currentUrl, baseUrl).pathname
return equals('url path').negate(path, actualPath)
return equals('url path').negate(normalizePath(path), normalizePath(actualPath))
}

/**
Expand Down Expand Up @@ -2487,22 +2498,23 @@ class WebDriver extends Helper {
async waitInUrl(urlPart, sec = null) {
const client = this.browser
const aSec = sec || this.options.waitForTimeoutInSeconds
const expectedUrl = resolveUrl(urlPart, this.options.url)
let currUrl = ''

return client
.waitUntil(
function () {
return this.getUrl().then(res => {
currUrl = decodeUrl(res)
return currUrl.indexOf(urlPart) > -1
return currUrl.indexOf(expectedUrl) > -1
})
},
{ timeout: aSec * 1000 },
)
.catch(e => {
e = wrapError(e)
if (e.message.indexOf('timeout')) {
throw new Error(`expected url to include ${urlPart}, but found ${currUrl}`)
throw new Error(`expected url to include ${expectedUrl}, but found ${currUrl}`)
}
throw e
})
Expand All @@ -2513,22 +2525,47 @@ class WebDriver extends Helper {
*/
async waitUrlEquals(urlPart, sec = null) {
const aSec = sec || this.options.waitForTimeoutInSeconds
const baseUrl = this.options.url
if (urlPart.indexOf('http') < 0) {
urlPart = baseUrl + urlPart
}
const expectedUrl = resolveUrl(urlPart, this.options.url)
let currUrl = ''
return this.browser
.waitUntil(function () {
return this.getUrl().then(res => {
currUrl = decodeUrl(res)
return currUrl === urlPart
return currUrl === expectedUrl
})
}, aSec * 1000)
.catch(e => {
e = wrapError(e)
if (e.message.indexOf('timeout')) {
throw new Error(`expected url to be ${urlPart}, but found ${currUrl}`)
throw new Error(`expected url to be ${expectedUrl}, but found ${currUrl}`)
}
throw e
})
}

/**
* {{> waitCurrentPathEquals }}
*/
async waitCurrentPathEquals(path, sec = null) {
const aSec = sec || this.options.waitForTimeoutInSeconds
const normalizedPath = normalizePath(path)
const baseUrl = this.options.url || 'http://localhost'
let actualPath = ''

return this.browser
.waitUntil(
async () => {
const currUrl = await this.browser.getUrl()
const url = new URL(currUrl, baseUrl)
actualPath = url.pathname
return normalizePath(actualPath) === normalizedPath
},
{ timeout: aSec * 1000 },
)
.catch(e => {
e = wrapError(e)
if (e.message.indexOf('timeout')) {
throw new Error(`expected path to be ${normalizedPath}, but found ${normalizePath(actualPath)}`)
}
throw e
})
Expand Down
18 changes: 18 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,24 @@ export const decodeUrl = function (url) {
return decodeURIComponent(decodeURIComponent(decodeURIComponent(url)))
}

export const normalizePath = function (path) {
if (path === '' || path === '/') return '/'
return path
.replace(/\/+/g, '/')
.replace(/\/$/, '') || '/'
}

export const resolveUrl = function (url, baseUrl) {
if (!url) return url
if (url.indexOf('http') === 0) return url
if (!baseUrl) return url
try {
return new URL(url, baseUrl).href
} catch (e) {
return url
}
}

export const xpathLocator = {
/**
* @param {string} string
Expand Down
Loading
Loading