diff --git a/lib/helper/Playwright.js b/lib/helper/Playwright.js index 2ecbf0336..5e26afe9b 100644 --- a/lib/helper/Playwright.js +++ b/lib/helper/Playwright.js @@ -23,6 +23,7 @@ import { clearString, requireWithFallback, normalizeSpacesInString, + normalizePath, relativeDir, } from '../utils.js' import { isColorProperty, convertColorToRGBA } from '../colorUtils.js' @@ -2412,7 +2413,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)) } /** @@ -2422,7 +2423,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)) } /** diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js index 0bf8e465c..f997ddb25 100644 --- a/lib/helper/Puppeteer.js +++ b/lib/helper/Puppeteer.js @@ -26,6 +26,7 @@ import { isModifierKey, requireWithFallback, normalizeSpacesInString, + normalizePath, } from '../utils.js' import { isColorProperty, convertColorToRGBA } from '../colorUtils.js' import ElementNotFound from './errors/ElementNotFound.js' @@ -1691,7 +1692,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)) } /** @@ -1701,7 +1702,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)) } /** diff --git a/lib/helper/WebDriver.js b/lib/helper/WebDriver.js index e07234a53..359bd44b2 100644 --- a/lib/helper/WebDriver.js +++ b/lib/helper/WebDriver.js @@ -13,7 +13,17 @@ 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, +} from '../utils.js' import { isColorProperty, convertColorToRGBA } from '../colorUtils.js' import ElementNotFound from './errors/ElementNotFound.js' import ConnectionRefused from './errors/ConnectionRefused.js' @@ -1851,7 +1861,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)) } /** @@ -1861,7 +1871,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)) } /** diff --git a/lib/utils.js b/lib/utils.js index 1458f387c..f3029d60f 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -150,6 +150,13 @@ 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 xpathLocator = { /** * @param {string} string diff --git a/test/helper/webapi.js b/test/helper/webapi.js index 842a9d81b..212b3cebe 100644 --- a/test/helper/webapi.js +++ b/test/helper/webapi.js @@ -114,6 +114,42 @@ export function tests() { await I.seeCurrentPathEquals('/info') await I.dontSeeCurrentPathEquals('/info#section') }) + + it('should normalize trailing slashes in path comparison', async () => { + await I.amOnPage('/info/') + await I.seeCurrentPathEquals('/info') + await I.seeCurrentPathEquals('/info/') + + await I.amOnPage('/users/') + await I.seeCurrentPathEquals('/users') + await I.seeCurrentPathEquals('/users/') + }) + + it('should normalize multiple consecutive slashes in path', async () => { + await I.amOnPage('/users//1') + await I.seeCurrentPathEquals('/users/1') + await I.seeCurrentPathEquals('/users//1') + + await I.amOnPage('/info///test') + await I.seeCurrentPathEquals('/info/test') + }) + + it('should handle root path correctly', async () => { + await I.amOnPage('/') + await I.seeCurrentPathEquals('/') + await I.seeCurrentPathEquals('') + await I.dontSeeCurrentPathEquals('/info') + }) + + it('should normalize both expected and actual paths', async () => { + await I.amOnPage('/users/') + await I.seeCurrentPathEquals('/users/') + await I.seeCurrentPathEquals('/users') + + await I.amOnPage('/users//1/') + await I.seeCurrentPathEquals('/users/1') + await I.seeCurrentPathEquals('/users/1/') + }) }) describe('#waitInUrl, #waitUrlEquals', () => {