Skip to content

feat(webapi): add waitForCookie #4169

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Feb 4, 2024
Merged
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
15 changes: 15 additions & 0 deletions docs/helpers/Playwright.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
15 changes: 15 additions & 0 deletions docs/helpers/Puppeteer.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
15 changes: 15 additions & 0 deletions docs/helpers/WebDriver.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
9 changes: 9 additions & 0 deletions docs/webapi/waitForCookie.mustache
Original file line number Diff line number Diff line change
@@ -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
34 changes: 34 additions & 0 deletions lib/helper/Playwright.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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(`Cookie ${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);
}
Expand Down
33 changes: 33 additions & 0 deletions lib/helper/Puppeteer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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(`Cookie ${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 }}
*/
Expand Down
32 changes: 32 additions & 0 deletions lib/helper/WebDriver.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -1860,6 +1861,37 @@ 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 cookie = await this.browser.getCookies([name]);
if (cookie.length === 0) throw Error(`Cookie ${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
Expand Down
27 changes: 26 additions & 1 deletion test/helper/webapi.js
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down Expand Up @@ -889,6 +889,31 @@ module.exports.tests = function () {
await I.clearCookie();
await I.dontSeeCookie('auth');
});

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 {
await I.waitForCookie('auth', 2);
} catch (e) {
assert.equal(e.message, 'Cookie auth is not found after 2s');
}
});

it('should wait for cookie', async () => {
if (isHelper('TestCafe')) return;
if (process.env.DevTools) return;

await I.amOnPage('/');
await I.setCookie({
name: 'auth',
value: '123456',
url: 'http://localhost',
});
await I.waitForCookie('auth');
});
});

describe('#waitForText', () => {
Expand Down