From 08a3eb6bbf2a8ab8a490688a74d9f9940b91bda8 Mon Sep 17 00:00:00 2001 From: kobenguyent Date: Thu, 1 Feb 2024 17:31:14 +0100 Subject: [PATCH 1/7] feat(webapi): add waitForCookie --- docs/helpers/Playwright.md | 15 +++++++++++++ docs/helpers/Puppeteer.md | 15 +++++++++++++ docs/helpers/WebDriver.md | 15 +++++++++++++ docs/webapi/waitForCookie.mustache | 9 ++++++++ lib/helper/Playwright.js | 34 ++++++++++++++++++++++++++++++ lib/helper/Puppeteer.js | 33 +++++++++++++++++++++++++++++ lib/helper/WebDriver.js | 33 +++++++++++++++++++++++++++++ test/helper/webapi.js | 21 +++++++++++++++++- 8 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 docs/webapi/waitForCookie.mustache diff --git a/docs/helpers/Playwright.md b/docs/helpers/Playwright.md index 326b41c24..5337c18f1 100644 --- a/docs/helpers/Playwright.md +++ b/docs/helpers/Playwright.md @@ -2398,6 +2398,21 @@ I.waitForClickable('.btn.continue', 5); // wait for 5 secs Returns **void** automatically synchronized promise through #recorder +### waitForCookie + +Waits for the specified cookie in the cookies. + +```js +I.waitForCookie("token"); +``` + +#### Parameters + +- `name` **[string][9]** expected cookie name. +- `sec` **[number][20]** (optional, `3` by default) time in seconds to wait + +Returns **void** automatically synchronized promise through #recorder + ### waitForDetached Waits for an element to become not attached to the DOM on a page (by default waits for 1sec). diff --git a/docs/helpers/Puppeteer.md b/docs/helpers/Puppeteer.md index 14e9630c4..4e2ff0383 100644 --- a/docs/helpers/Puppeteer.md +++ b/docs/helpers/Puppeteer.md @@ -2003,6 +2003,21 @@ I.waitForClickable('.btn.continue', 5); // wait for 5 secs Returns **void** automatically synchronized promise through #recorder +### waitForCookie + +Waits for the specified cookie in the cookies. + +```js +I.waitForCookie("token"); +``` + +#### Parameters + +- `name` **[string][6]** expected cookie name. +- `sec` **[number][10]** (optional, `3` by default) time in seconds to wait + +Returns **void** automatically synchronized promise through #recorder + ### waitForDetached Waits for an element to become not attached to the DOM on a page (by default waits for 1sec). diff --git a/docs/helpers/WebDriver.md b/docs/helpers/WebDriver.md index 839cd7ad4..cbc9c2f29 100644 --- a/docs/helpers/WebDriver.md +++ b/docs/helpers/WebDriver.md @@ -2253,6 +2253,21 @@ I.waitForClickable('.btn.continue', 5); // wait for 5 secs Returns **void** automatically synchronized promise through #recorder +### waitForCookie + +Waits for the specified cookie in the cookies. + +```js +I.waitForCookie("token"); +``` + +#### Parameters + +- `name` **[string][18]** expected cookie name. +- `sec` **[number][23]** (optional, `3` by default) time in seconds to wait + +Returns **void** automatically synchronized promise through #recorder + ### waitForDetached Waits for an element to become not attached to the DOM on a page (by default waits for 1sec). diff --git a/docs/webapi/waitForCookie.mustache b/docs/webapi/waitForCookie.mustache new file mode 100644 index 000000000..ae1419be9 --- /dev/null +++ b/docs/webapi/waitForCookie.mustache @@ -0,0 +1,9 @@ +Waits for the specified cookie in the cookies. + +```js +I.waitForCookie("token"); +``` + +@param {string} name expected cookie name. +@param {number} [sec=3] (optional, `3` by default) time in seconds to wait +@returns {void} automatically synchronized promise through #recorder diff --git a/lib/helper/Playwright.js b/lib/helper/Playwright.js index 4f9816cbc..ec0ad3c05 100644 --- a/lib/helper/Playwright.js +++ b/lib/helper/Playwright.js @@ -4,6 +4,7 @@ const fs = require('fs'); const Helper = require('@codeceptjs/helper'); const { v4: uuidv4 } = require('uuid'); const assert = require('assert'); +const promiseRetry = require('promise-retry'); const Locator = require('../locator'); const store = require('../store'); const recorder = require('../recorder'); @@ -50,6 +51,7 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright const { seeElementError, dontSeeElementError, dontSeeElementInDOMError, seeElementInDOMError, } = require('./errors/ElementAssertion'); +const { log } = require('../output'); const pathSeparator = path.sep; @@ -2890,6 +2892,38 @@ class Playwright extends Helper { } } + /** + * {{> waitForCookie }} + */ + async waitForCookie(name, sec) { + // by default, we will retry 3 times + let retries = 3; + const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout; + + if (sec) { + retries = sec; + } else { + retries = Math.ceil(waitTimeout / 1000) - 1; + } + + return promiseRetry(async (retry, number) => { + const _grabCookie = async (name) => { + const cookies = await this.browserContext.cookies(); + const cookie = cookies.filter(c => c.name === name); + if (cookie.length === 0) throw Error(`${name} is not found after ${retries}s`); + }; + + this.debugSection('Wait for cookie: ', name); + if (number > 1) this.debugSection('Retrying... Attempt #', number); + + try { + await _grabCookie(name); + } catch (e) { + retry(e); + } + }, { retries, maxTimeout: 1000 }); + } + async _waitForAction() { return this.wait(this.options.waitForAction / 1000); } diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js index ee05f283b..a159f859e 100644 --- a/lib/helper/Puppeteer.js +++ b/lib/helper/Puppeteer.js @@ -5,6 +5,7 @@ const path = require('path'); const Helper = require('@codeceptjs/helper'); const { v4: uuidv4 } = require('uuid'); +const promiseRetry = require('promise-retry'); const Locator = require('../locator'); const recorder = require('../recorder'); const store = require('../store'); @@ -1635,6 +1636,38 @@ class Puppeteer extends Helper { if (cookie[0]) return cookie[0]; } + /** + * {{> waitForCookie }} + */ + async waitForCookie(name, sec) { + // by default, we will retry 3 times + let retries = 3; + const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout; + + if (sec) { + retries = sec; + } else { + retries = Math.ceil(waitTimeout / 1000) - 1; + } + + return promiseRetry(async (retry, number) => { + const _grabCookie = async (name) => { + const cookies = await this.page.cookies(); + const cookie = cookies.filter(c => c.name === name); + if (cookie.length === 0) throw Error(`${name} is not found after ${retries}s`); + }; + + this.debugSection('Wait for cookie: ', name); + if (number > 1) this.debugSection('Retrying... Attempt #', number); + + try { + await _grabCookie(name); + } catch (e) { + retry(e); + } + }, { retries, maxTimeout: 1000 }); + } + /** * {{> clearCookie }} */ diff --git a/lib/helper/WebDriver.js b/lib/helper/WebDriver.js index 5a3b4220e..5b692681e 100644 --- a/lib/helper/WebDriver.js +++ b/lib/helper/WebDriver.js @@ -6,6 +6,7 @@ const fs = require('fs'); const Helper = require('@codeceptjs/helper'); const crypto = require('crypto'); +const promiseRetry = require('promise-retry'); const stringIncludes = require('../assert/include').includes; const { urlEquals, equals } = require('../assert/equal'); const { debug } = require('../output'); @@ -1860,6 +1861,38 @@ class WebDriver extends Helper { return cookie[0]; } + /** + * {{> waitForCookie }} + */ + async waitForCookie(name, sec) { + // by default, we will retry 3 times + let retries = 3; + const waitTimeout = sec || this.options.waitForTimeoutInSeconds; + + if (sec) { + retries = sec; + } else { + retries = waitTimeout - 1; + } + + return promiseRetry(async (retry, number) => { + const _grabCookie = async (name) => { + const cookies = await this.browser.cookies(); + const cookie = cookies.filter(c => c.name === name); + if (cookie.length === 0) throw Error(`${name} is not found after ${retries}s`); + }; + + this.debugSection('Wait for cookie: ', name); + if (number > 1) this.debugSection('Retrying... Attempt #', number); + + try { + await _grabCookie(name); + } catch (e) { + retry(e); + } + }, { retries, maxTimeout: 1000 }); + } + /** * Accepts the active JavaScript native popup window, as created by window.alert|window.confirm|window.prompt. * Don't confuse popups with modal windows, as created by [various diff --git a/test/helper/webapi.js b/test/helper/webapi.js index e50d2ffbd..868a8f870 100644 --- a/test/helper/webapi.js +++ b/test/helper/webapi.js @@ -842,7 +842,7 @@ module.exports.tests = function () { }); }); - describe('cookies : #setCookie, #clearCookies, #seeCookie', () => { + describe('cookies : #setCookie, #clearCookies, #seeCookie, #waitForCookie', () => { it('should do all cookie stuff', async () => { await I.amOnPage('/'); await I.setCookie({ @@ -889,6 +889,25 @@ module.exports.tests = function () { await I.clearCookie(); await I.dontSeeCookie('auth'); }); + + it('should wait for cookie and throw error when cookie not found', async () => { + await I.amOnPage('https://google.com'); + try { + await I.waitForCookie('auth', 2); + } catch (e) { + assert.equal(e.message, 'auth is not found after 2s'); + } + }); + + it('should wait for cookie', async () => { + await I.amOnPage('https://google.com'); + await I.setCookie({ + name: 'auth', + value: '123456', + url: 'https://google.com', + }); + await I.waitForCookie('auth'); + }); }); describe('#waitForText', () => { From 22722afc3f924660975c9a7e0e6c4ade3241b512 Mon Sep 17 00:00:00 2001 From: kobenguyent Date: Thu, 1 Feb 2024 17:39:08 +0100 Subject: [PATCH 2/7] feat(webapi): add waitForCookie --- test/helper/webapi.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/helper/webapi.js b/test/helper/webapi.js index 868a8f870..9607b210b 100644 --- a/test/helper/webapi.js +++ b/test/helper/webapi.js @@ -891,6 +891,8 @@ module.exports.tests = function () { }); it('should wait for cookie and throw error when cookie not found', async () => { + if (isHelper('TestCafe')) this.skip(); + await I.amOnPage('https://google.com'); try { await I.waitForCookie('auth', 2); @@ -900,6 +902,8 @@ module.exports.tests = function () { }); it('should wait for cookie', async () => { + if (isHelper('TestCafe')) this.skip(); + await I.amOnPage('https://google.com'); await I.setCookie({ name: 'auth', From 7400b0d10b4f8c953ea72c3247d480a4e101eaff Mon Sep 17 00:00:00 2001 From: kobenguyent Date: Thu, 1 Feb 2024 17:40:19 +0100 Subject: [PATCH 3/7] feat(webapi): add waitForCookie --- lib/helper/Playwright.js | 2 +- lib/helper/Puppeteer.js | 2 +- lib/helper/WebDriver.js | 2 +- test/helper/webapi.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/helper/Playwright.js b/lib/helper/Playwright.js index ec0ad3c05..df672e07a 100644 --- a/lib/helper/Playwright.js +++ b/lib/helper/Playwright.js @@ -2910,7 +2910,7 @@ class Playwright extends Helper { const _grabCookie = async (name) => { const cookies = await this.browserContext.cookies(); const cookie = cookies.filter(c => c.name === name); - if (cookie.length === 0) throw Error(`${name} is not found after ${retries}s`); + if (cookie.length === 0) throw Error(`Cookie ${name} is not found after ${retries}s`); }; this.debugSection('Wait for cookie: ', name); diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js index a159f859e..16f5b4aa9 100644 --- a/lib/helper/Puppeteer.js +++ b/lib/helper/Puppeteer.js @@ -1654,7 +1654,7 @@ class Puppeteer extends Helper { const _grabCookie = async (name) => { const cookies = await this.page.cookies(); const cookie = cookies.filter(c => c.name === name); - if (cookie.length === 0) throw Error(`${name} is not found after ${retries}s`); + if (cookie.length === 0) throw Error(`Cookie ${name} is not found after ${retries}s`); }; this.debugSection('Wait for cookie: ', name); diff --git a/lib/helper/WebDriver.js b/lib/helper/WebDriver.js index 5b692681e..389c7ae8a 100644 --- a/lib/helper/WebDriver.js +++ b/lib/helper/WebDriver.js @@ -1879,7 +1879,7 @@ class WebDriver extends Helper { const _grabCookie = async (name) => { const cookies = await this.browser.cookies(); const cookie = cookies.filter(c => c.name === name); - if (cookie.length === 0) throw Error(`${name} is not found after ${retries}s`); + if (cookie.length === 0) throw Error(`Cookie ${name} is not found after ${retries}s`); }; this.debugSection('Wait for cookie: ', name); diff --git a/test/helper/webapi.js b/test/helper/webapi.js index 9607b210b..68134ec9c 100644 --- a/test/helper/webapi.js +++ b/test/helper/webapi.js @@ -897,7 +897,7 @@ module.exports.tests = function () { try { await I.waitForCookie('auth', 2); } catch (e) { - assert.equal(e.message, 'auth is not found after 2s'); + assert.equal(e.message, 'Cookie auth is not found after 2s'); } }); From 2130c85e7c220986ba318fbf587bd6dd56a07336 Mon Sep 17 00:00:00 2001 From: kobenguyent Date: Thu, 1 Feb 2024 17:45:06 +0100 Subject: [PATCH 4/7] feat(webapi): add waitForCookie --- test/helper/webapi.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/helper/webapi.js b/test/helper/webapi.js index 68134ec9c..9c1e0cc50 100644 --- a/test/helper/webapi.js +++ b/test/helper/webapi.js @@ -891,7 +891,7 @@ module.exports.tests = function () { }); it('should wait for cookie and throw error when cookie not found', async () => { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) return; await I.amOnPage('https://google.com'); try { @@ -902,7 +902,7 @@ module.exports.tests = function () { }); it('should wait for cookie', async () => { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) return; await I.amOnPage('https://google.com'); await I.setCookie({ From 4de923d40d643f5d5171e14901fd8373fc33ec43 Mon Sep 17 00:00:00 2001 From: KobeN <7845001+kobenguyent@users.noreply.github.com> Date: Thu, 1 Feb 2024 18:05:28 +0100 Subject: [PATCH 5/7] fix: wrong method --- lib/helper/WebDriver.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/helper/WebDriver.js b/lib/helper/WebDriver.js index 389c7ae8a..648b6219c 100644 --- a/lib/helper/WebDriver.js +++ b/lib/helper/WebDriver.js @@ -1877,8 +1877,7 @@ class WebDriver extends Helper { return promiseRetry(async (retry, number) => { const _grabCookie = async (name) => { - const cookies = await this.browser.cookies(); - const cookie = cookies.filter(c => c.name === name); + const cookie = await this.browser.getCookies([name]); if (cookie.length === 0) throw Error(`Cookie ${name} is not found after ${retries}s`); }; From aff51a282855b189312a352c5c3093b0dd15b8d4 Mon Sep 17 00:00:00 2001 From: KobeN <7845001+kobenguyent@users.noreply.github.com> Date: Thu, 1 Feb 2024 18:19:37 +0100 Subject: [PATCH 6/7] fix: UTs --- test/helper/webapi.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/helper/webapi.js b/test/helper/webapi.js index 9c1e0cc50..19d04a708 100644 --- a/test/helper/webapi.js +++ b/test/helper/webapi.js @@ -892,6 +892,7 @@ module.exports.tests = function () { it('should wait for cookie and throw error when cookie not found', async () => { if (isHelper('TestCafe')) return; + if (process.env.DevTools) return; await I.amOnPage('https://google.com'); try { @@ -903,6 +904,7 @@ module.exports.tests = function () { it('should wait for cookie', async () => { if (isHelper('TestCafe')) return; + if (process.env.DevTools) return; await I.amOnPage('https://google.com'); await I.setCookie({ From 9a9ea8ac790c4daa14e63704eae00d610a358f8c Mon Sep 17 00:00:00 2001 From: kobenguyent Date: Fri, 2 Feb 2024 06:32:14 +0100 Subject: [PATCH 7/7] fix: UTs --- test/helper/webapi.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/helper/webapi.js b/test/helper/webapi.js index 19d04a708..20c4c0b09 100644 --- a/test/helper/webapi.js +++ b/test/helper/webapi.js @@ -906,11 +906,11 @@ module.exports.tests = function () { if (isHelper('TestCafe')) return; if (process.env.DevTools) return; - await I.amOnPage('https://google.com'); + await I.amOnPage('/'); await I.setCookie({ name: 'auth', value: '123456', - url: 'https://google.com', + url: 'http://localhost', }); await I.waitForCookie('auth'); });