From f0b4eca48ba7c22fa401180e058ab53faf2c004f Mon Sep 17 00:00:00 2001 From: DavertMik Date: Fri, 6 Feb 2026 07:24:18 +0200 Subject: [PATCH 1/2] Add seeCurrentPathEquals method to ignore query strings Adds new assertion method to check URL path equality while ignoring query parameters and URL fragments. - I.seeCurrentPathEquals('/info') passes for '/info?user=1', '/info#section' - I.seeCurrentPathEquals('/') passes for '/', '/?user=ok', '/#top' Implemented in Playwright, Puppeteer, and WebDriver helpers using native URL class for pathname extraction. Co-Authored-By: Claude Opus 4.5 --- docs/webapi/seeCurrentPathEquals.mustache | 10 ++++++ lib/helper/Playwright.js | 10 ++++++ lib/helper/Puppeteer.js | 10 ++++++ lib/helper/WebDriver.js | 10 ++++++ test/helper/webapi.js | 39 +++++++++++++++++++++++ 5 files changed, 79 insertions(+) create mode 100644 docs/webapi/seeCurrentPathEquals.mustache diff --git a/docs/webapi/seeCurrentPathEquals.mustache b/docs/webapi/seeCurrentPathEquals.mustache new file mode 100644 index 000000000..1b3d8d4d7 --- /dev/null +++ b/docs/webapi/seeCurrentPathEquals.mustache @@ -0,0 +1,10 @@ +Checks that current URL path matches the expected path. +Query strings and URL fragments are ignored. + +```js +I.seeCurrentPathEquals('/info'); // passes for '/info', '/info?user=1', '/info#section' +I.seeCurrentPathEquals('/'); // passes for '/', '/?user=ok', '/#top' +``` + +@param {string} path value to check. +@returns {void} automatically synchronized promise through #recorder diff --git a/lib/helper/Playwright.js b/lib/helper/Playwright.js index 71c48e9db..7df1a521b 100644 --- a/lib/helper/Playwright.js +++ b/lib/helper/Playwright.js @@ -2405,6 +2405,16 @@ class Playwright extends Helper { urlEquals(this.options.url).negate(url, await this._getPageUrl()) } + /** + * {{> seeCurrentPathEquals }} + */ + async seeCurrentPathEquals(path) { + 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) + } + /** * {{> see }} * diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js index 5bddc336e..9fa62f7ea 100644 --- a/lib/helper/Puppeteer.js +++ b/lib/helper/Puppeteer.js @@ -1684,6 +1684,16 @@ class Puppeteer extends Helper { urlEquals(this.options.url).negate(url, await this._getPageUrl()) } + /** + * {{> seeCurrentPathEquals }} + */ + async seeCurrentPathEquals(path) { + 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) + } + /** * {{> see }} * diff --git a/lib/helper/WebDriver.js b/lib/helper/WebDriver.js index c602c5dd7..156a82200 100644 --- a/lib/helper/WebDriver.js +++ b/lib/helper/WebDriver.js @@ -1844,6 +1844,16 @@ class WebDriver extends Helper { return urlEquals(this.options.url).negate(url, decodeUrl(res)) } + /** + * {{> seeCurrentPathEquals }} + */ + async seeCurrentPathEquals(path) { + const currentUrl = await this.browser.getUrl() + const baseUrl = this.options.url || 'http://localhost' + const actualPath = new URL(currentUrl, baseUrl).pathname + return assert.equal(path, actualPath, `expected url path to be ${path}, but found ${actualPath}`) + } + /** * Wraps [execute](http://webdriver.io/api/protocol/execute.html) command. * diff --git a/test/helper/webapi.js b/test/helper/webapi.js index 16ba7567e..842a9d81b 100644 --- a/test/helper/webapi.js +++ b/test/helper/webapi.js @@ -75,6 +75,45 @@ export function tests() { const url = await I.grabCurrentUrl() assert.equal(url, `${siteUrl}/info`) }) + + it('should check for equality with query strings', async () => { + await I.amOnPage('/info?user=test') + // Query strings matter for exact equality + await I.seeCurrentUrlEquals('/info?user=test') + await I.dontSeeCurrentUrlEquals('/info') + // But substring check works + await I.seeInCurrentUrl('/info') + await I.seeInCurrentUrl('user=test') + }) + + it('should handle root path with query strings', async () => { + await I.amOnPage('/?user=ok') + // Query strings matter - exact equality requires query string + await I.seeCurrentUrlEquals('/?user=ok') + await I.dontSeeCurrentUrlEquals('/') + // But substring check works for path fragment + await I.seeInCurrentUrl('/') + }) + + it('should check path equality ignoring query strings', async () => { + await I.amOnPage('/info?user=test') + // Path equality ignores query strings + await I.seeCurrentPathEquals('/info') + await I.dontSeeCurrentPathEquals('/form') + await I.dontSeeCurrentPathEquals('/info?user=test') + }) + + it('should check root path equality ignoring query strings', async () => { + await I.amOnPage('/?user=ok') + await I.seeCurrentPathEquals('/') + await I.dontSeeCurrentPathEquals('/info') + }) + + it('should check path equality ignoring hash fragments', async () => { + await I.amOnPage('/info#section') + await I.seeCurrentPathEquals('/info') + await I.dontSeeCurrentPathEquals('/info#section') + }) }) describe('#waitInUrl, #waitUrlEquals', () => { From e6a96494595141ae76d811e3729aa9f684e5c526 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Fri, 6 Feb 2026 14:09:54 +0200 Subject: [PATCH 2/2] Add dontSeeCurrentPathEquals method for negative path assertions Adds the negative counterpart to seeCurrentPathEquals for checking that URL paths do not match, ignoring query strings and fragments. Co-Authored-By: Claude Opus 4.5 --- docs/webapi/dontSeeCurrentPathEquals.mustache | 10 ++++++++++ lib/helper/Playwright.js | 10 ++++++++++ lib/helper/Puppeteer.js | 10 ++++++++++ lib/helper/WebDriver.js | 12 ++++++++++++ 4 files changed, 42 insertions(+) create mode 100644 docs/webapi/dontSeeCurrentPathEquals.mustache diff --git a/docs/webapi/dontSeeCurrentPathEquals.mustache b/docs/webapi/dontSeeCurrentPathEquals.mustache new file mode 100644 index 000000000..7142f8560 --- /dev/null +++ b/docs/webapi/dontSeeCurrentPathEquals.mustache @@ -0,0 +1,10 @@ +Checks that current URL path does NOT match the expected path. +Query strings and URL fragments are ignored. + +```js +I.dontSeeCurrentPathEquals('/form'); // fails for '/form', '/form?user=1', '/form#section' +I.dontSeeCurrentPathEquals('/'); // fails for '/', '/?user=ok', '/#top' +``` + +@param {string} path value to check. +@returns {void} automatically synchronized promise through #recorder diff --git a/lib/helper/Playwright.js b/lib/helper/Playwright.js index 7df1a521b..2ecbf0336 100644 --- a/lib/helper/Playwright.js +++ b/lib/helper/Playwright.js @@ -2415,6 +2415,16 @@ class Playwright extends Helper { return equals('url path').assert(path, actualPath) } + /** + * {{> dontSeeCurrentPathEquals }} + */ + async dontSeeCurrentPathEquals(path) { + 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) + } + /** * {{> see }} * diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js index 9fa62f7ea..0bf8e465c 100644 --- a/lib/helper/Puppeteer.js +++ b/lib/helper/Puppeteer.js @@ -1694,6 +1694,16 @@ class Puppeteer extends Helper { return equals('url path').assert(path, actualPath) } + /** + * {{> dontSeeCurrentPathEquals }} + */ + async dontSeeCurrentPathEquals(path) { + 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) + } + /** * {{> see }} * diff --git a/lib/helper/WebDriver.js b/lib/helper/WebDriver.js index 156a82200..3e31c8928 100644 --- a/lib/helper/WebDriver.js +++ b/lib/helper/WebDriver.js @@ -1854,6 +1854,18 @@ class WebDriver extends Helper { return assert.equal(path, actualPath, `expected url path to be ${path}, but found ${actualPath}`) } + /** + * {{> dontSeeCurrentPathEquals }} + */ + async dontSeeCurrentPathEquals(path) { + const currentUrl = await this.browser.getUrl() + const baseUrl = this.options.url || 'http://localhost' + const actualPath = new URL(currentUrl, baseUrl).pathname + const errorMessage = `expected url path not to be ${path}, but found ${actualPath}` + const isEqual = path === actualPath + if (isEqual) throw new Error(errorMessage) + } + /** * Wraps [execute](http://webdriver.io/api/protocol/execute.html) command. *