From d97e3fb44f889b160c2b877df919f7c023caa1cf Mon Sep 17 00:00:00 2001 From: Stefano Magni Date: Wed, 30 Oct 2019 15:09:09 +0100 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=F0=9F=90=9B=20Manage=20the=20log?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The official documentation suggests to customize the use of Cypress.log https://docs.cypress.io/api/cypress-api/cypress-log.html#Syntax Closes: #53 --- README.md | 12 +- cypress/integration/plugin.spec.js | 255 ++++++++++++++++++----------- cypress/types/plugin.spec.ts | 40 +++-- index.d.ts | 12 +- package.json | 2 +- src/index.js | 56 ++++--- 6 files changed, 240 insertions(+), 137 deletions(-) diff --git a/README.md b/README.md index 3b41bd7..793a305 100644 --- a/README.md +++ b/README.md @@ -128,11 +128,13 @@ A function that must return a truthy value when the wait is over. Pass in an options object to change the default behavior of `cy.waitUntil()`. -Option | Default | Description ---- | --- | --- -`errorMsg` | `Timed out retrying` | The error message to write. -`timeout` | `5000` | Time to wait for the `checkFunction` to return a truthy value before throwing an error. -`interval` | `200` | Time to wait between the `checkFunction` invocations. +| Option | Default | Description | +| ------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `errorMsg` | `Timed out retrying` | The error message to write. | +| `timeout` | `5000` | Time to wait for the `checkFunction` to return a truthy value before throwing an error. | +| `interval` | `200` | Time to wait between the `checkFunction` invocations. | +| `description` | `waitUntil` | The name logged into the Cypress Test Runner. | +| `logger` | `Cypress.log` | A custom logger in place of the default [Cypress.log](https://docs.cypress.io/api/cypress-api/cypress-log.html). It's useful just for debugging purposes. |

diff --git a/cypress/integration/plugin.spec.js b/cypress/integration/plugin.spec.js index d34dc41..4b3708f 100644 --- a/cypress/integration/plugin.spec.js +++ b/cypress/integration/plugin.spec.js @@ -1,132 +1,171 @@ /// -context('Actions', () => { +context("Cypress Wait Until", () => { beforeEach(() => { - cy.visit('http://localhost:5000/') - }) + cy.visit("http://localhost:5000/"); + }); - it('Should work with an immediately-satisfied condition', () => { - const COOKIE_NAME = 'immediate-cookie' - const EXPECTED_COOKIE_VALUE = 'Set' - cy.get('#' + COOKIE_NAME).click() + it("Should work with an immediately-satisfied condition", () => { + const COOKIE_NAME = "immediate-cookie"; + const EXPECTED_COOKIE_VALUE = "Set"; + cy.get("#" + COOKIE_NAME).click(); - const checkFunction = () => cy.getCookie(COOKIE_NAME) - .then(cookieValue => cookieValue && cookieValue.value === EXPECTED_COOKIE_VALUE) + const checkFunction = () => + cy + .getCookie(COOKIE_NAME) + .then(cookieValue => cookieValue && cookieValue.value === EXPECTED_COOKIE_VALUE); - cy.waitUntil(checkFunction) + cy.waitUntil(checkFunction); - cy.getCookie(COOKIE_NAME).then(cookieValue => expect(cookieValue.value).to.be.equal(EXPECTED_COOKIE_VALUE)); - }) + cy.getCookie(COOKIE_NAME).then(cookieValue => + expect(cookieValue.value).to.be.equal(EXPECTED_COOKIE_VALUE) + ); + }); - it('Should work with a condition satisfied after a random delay', () => { - const COOKIE_NAME = 'after-a-while-cookie' - const EXPECTED_COOKIE_VALUE = 'Set' - cy.get('#' + COOKIE_NAME).click() + it("Should work with a condition satisfied after a random delay", () => { + const COOKIE_NAME = "after-a-while-cookie"; + const EXPECTED_COOKIE_VALUE = "Set"; + cy.get("#" + COOKIE_NAME).click(); - const checkFunction = () => cy.getCookie(COOKIE_NAME) - .then(cookieValue => cookieValue && cookieValue.value === EXPECTED_COOKIE_VALUE) + const checkFunction = () => + cy + .getCookie(COOKIE_NAME) + .then(cookieValue => cookieValue && cookieValue.value === EXPECTED_COOKIE_VALUE); - cy.waitUntil(checkFunction) + cy.waitUntil(checkFunction); - cy.getCookie(COOKIE_NAME).then(cookieValue => expect(cookieValue.value).to.be.equal(EXPECTED_COOKIE_VALUE)); - }) + cy.getCookie(COOKIE_NAME).then(cookieValue => + expect(cookieValue.value).to.be.equal(EXPECTED_COOKIE_VALUE) + ); + }); - it('Should apply options correctly', () => { - const COOKIE_NAME = 'after-a-while-cookie' - const EXPECTED_COOKIE_VALUE = 'Set' + it("Should apply options correctly", () => { + const COOKIE_NAME = "after-a-while-cookie"; + const EXPECTED_COOKIE_VALUE = "Set"; - cy.once('fail', err => { - expect(err.message).to.be.equal('Timed out retrying') - }) + cy.once("fail", err => { + expect(err.message).to.be.equal("Timed out retrying"); + }); - cy.get('#' + COOKIE_NAME).click() + cy.get("#" + COOKIE_NAME).click(); - const checkFunction = () => cy.getCookie(COOKIE_NAME) - .then(cookieValue => cookieValue && cookieValue.value === EXPECTED_COOKIE_VALUE) + const checkFunction = () => + cy + .getCookie(COOKIE_NAME) + .then(cookieValue => cookieValue && cookieValue.value === EXPECTED_COOKIE_VALUE); cy.waitUntil(checkFunction, { interval: 100, timeout: 900 - }) - }) + }); + }); - it('Should check value equality check', () => { - const COOKIE_NAME = 'change-after-a-while-cookie' - const EXPECTED_COOKIE_VALUE = '7' - cy.get('#' + COOKIE_NAME).click() + it("Should log a custom logging description", () => { + const COOKIE_NAME = "after-a-while-cookie"; + const EXPECTED_COOKIE_VALUE = "Set"; - const checkFunction = () => cy.getCookie(COOKIE_NAME) - .then(cookieValue => cookieValue && cookieValue.value === EXPECTED_COOKIE_VALUE) + cy.once("fail", err => { + expect(err.message).to.be.equal("Timed out retrying"); + }); - cy.waitUntil(checkFunction) + cy.get("#" + COOKIE_NAME).click(); - cy.getCookie(COOKIE_NAME).then(cookieValue => expect(cookieValue.value).to.be.equal(EXPECTED_COOKIE_VALUE)); - }) + const checkFunction = () => + cy + .getCookie(COOKIE_NAME) + .then(cookieValue => cookieValue && cookieValue.value === EXPECTED_COOKIE_VALUE); - it('Should make the test fail with an unsatisfied condition', () => { - const COOKIE_NAME = 'unknwon-cookie' - const EXPECTED_COOKIE_VALUE = 'Set' + cy.waitUntil(checkFunction, { + interval: 100, + timeout: 900 + }); + }); + + it("Should check value equality check", () => { + const COOKIE_NAME = "change-after-a-while-cookie"; + const EXPECTED_COOKIE_VALUE = "7"; + cy.get("#" + COOKIE_NAME).click(); + + const checkFunction = () => + cy + .getCookie(COOKIE_NAME) + .then(cookieValue => cookieValue && cookieValue.value === EXPECTED_COOKIE_VALUE); + + cy.waitUntil(checkFunction); + + cy.getCookie(COOKIE_NAME).then(cookieValue => + expect(cookieValue.value).to.be.equal(EXPECTED_COOKIE_VALUE) + ); + }); + + it("Should make the test fail with an unsatisfied condition", () => { + const COOKIE_NAME = "unknwon-cookie"; + const EXPECTED_COOKIE_VALUE = "Set"; - cy.once('fail', err => { - expect(err.message).to.be.equal('Timed out retrying') - }) + cy.once("fail", err => { + expect(err.message).to.be.equal("Timed out retrying"); + }); - const checkFunction = () => cy.getCookie(COOKIE_NAME) - .then(cookieValue => cookieValue && cookieValue.value === EXPECTED_COOKIE_VALUE) + const checkFunction = () => + cy + .getCookie(COOKIE_NAME) + .then(cookieValue => cookieValue && cookieValue.value === EXPECTED_COOKIE_VALUE); - cy.waitUntil(checkFunction) - }) + cy.waitUntil(checkFunction); + }); - it('Should work sync', () => { - const checkFunction = () => true + it("Should work sync", () => { + const checkFunction = () => true; - cy.waitUntil(checkFunction) - }) + cy.waitUntil(checkFunction); + }); - it('Should work sync with retries', () => { + it("Should work sync with retries", () => { let n = 4; const checkFunction = () => { n--; return n < 0; - } + }; - cy.waitUntil(checkFunction) - }) + cy.waitUntil(checkFunction); + }); - it('`checkFunction` should be a function', () => { - const ERROR_MESSAGE = '`checkFunction` parameter should be a function. Found: true' + it("`checkFunction` should be a function", () => { + const ERROR_MESSAGE = "`checkFunction` parameter should be a function. Found: true"; - cy.once('fail', err => expect(err.message).to.be.equal(ERROR_MESSAGE)) - cy.waitUntil(true) - }) + cy.once("fail", err => expect(err.message).to.be.equal(ERROR_MESSAGE)); + cy.waitUntil(true); + }); - it('Should accept a custom error message', () => { - const COOKIE_NAME = 'unknwon-cookie' - const EXPECTED_COOKIE_VALUE = 'Set' + it("Should accept a custom error message", () => { + const COOKIE_NAME = "unknwon-cookie"; + const EXPECTED_COOKIE_VALUE = "Set"; - cy.once('fail', err => { - expect(err.message).to.be.equal('Custom error message') - }) + cy.once("fail", err => { + expect(err.message).to.be.equal("Custom error message"); + }); - const checkFunction = () => cy.getCookie(COOKIE_NAME) - .then(cookieValue => cookieValue && cookieValue.value === EXPECTED_COOKIE_VALUE) + const checkFunction = () => + cy + .getCookie(COOKIE_NAME) + .then(cookieValue => cookieValue && cookieValue.value === EXPECTED_COOKIE_VALUE); - cy.waitUntil(checkFunction, {errorMsg: 'Custom error message'}) - }) + cy.waitUntil(checkFunction, { errorMsg: "Custom error message" }); + }); - it('Should pass the result to the next command', () => { + it("Should pass the result to the next command", () => { const result = 10; const checkFunction = () => result; const asyncCheckFunction = () => Promise.resolve(result); const chainableCheckFunction = () => cy.wrap(result).then(wrappedResult => wrappedResult); - cy.waitUntil(checkFunction).should('eq', result) - cy.waitUntil(asyncCheckFunction).should('eq', result) - cy.waitUntil(chainableCheckFunction).should('eq', result) - }) + cy.waitUntil(checkFunction).should("eq", result); + cy.waitUntil(asyncCheckFunction).should("eq", result); + cy.waitUntil(chainableCheckFunction).should("eq", result); + }); - it('Should wait between every check', () => { + it("Should wait between every check", () => { const interval = 100; let previousTimestamp; @@ -134,34 +173,64 @@ context('Actions', () => { const previousTimestampBackup = previousTimestamp; const newTimestamp = Date.now(); previousTimestamp = newTimestamp; - if(previousTimestampBackup) { + if (previousTimestampBackup) { const diff = newTimestamp - previousTimestampBackup; return diff >= interval; } - return false - } + return false; + }; const asyncCheckFunction = () => Promise.resolve(checkFunction()); const chainableCheckFunction = () => cy.wrap().then(() => checkFunction()); cy.log("Sync function"); - cy.waitUntil(checkFunction, {interval}) + cy.waitUntil(checkFunction, { interval }); cy.log("Async function"); - cy.waitUntil(asyncCheckFunction, {interval}) + cy.waitUntil(asyncCheckFunction, { interval }); cy.log("Chainable function"); - cy.waitUntil(chainableCheckFunction, {interval}) - }) + cy.waitUntil(chainableCheckFunction, { interval }); + }); - it('Should be chainable', () => { + it("Should be chainable", () => { const result = 10; const checkFunction = () => result; const checkFunctionWithSubject = subject => subject; - cy.waitUntil(checkFunction) - .should('eq', result) + cy.waitUntil(checkFunction).should("eq", result); cy.wrap(result) .waitUntil(checkFunctionWithSubject) - .should('eq', result) - }) -}) + .should("eq", result); + }); + + it("Should leverage Cypress.log", () => { + const checkFunction = () => true; + + const logger = { + log: (...params) => Cypress.log(...params) + }; + const spy = cy.spy(logger, "log"); + + cy.waitUntil(checkFunction, { logger: logger.log }).then(() => { + expect(spy).to.have.been.called; + const lastCallArgs = spy.lastCall.args[0]; + expect(lastCallArgs).deep.include({ name: "waitUntil" }); + }); + }); + + it("Should accept a custom log description", () => { + const checkFunction = () => true; + const description = "custom description"; + + const logger = { + log: (...params) => Cypress.log(...params) + }; + const spy = cy.spy(logger, "log"); + + cy.waitUntil(checkFunction, { logger: logger.log, description }).then(() => { + expect(spy).to.have.been.called; + const lastCallArgs = spy.lastCall.args[0]; + expect(lastCallArgs).deep.include({ name: description }); + }); + }); +}); diff --git a/cypress/types/plugin.spec.ts b/cypress/types/plugin.spec.ts index 5fde338..d86ca93 100644 --- a/cypress/types/plugin.spec.ts +++ b/cypress/types/plugin.spec.ts @@ -1,21 +1,29 @@ /// -cy.waitUntil(() => true) -cy.waitUntil(() => false) -cy.waitUntil(() => Promise.resolve(true)) -cy.waitUntil(() => Promise.resolve(false)) +cy.waitUntil(() => true); +cy.waitUntil(() => false); +cy.waitUntil(() => Promise.resolve(true)); +cy.waitUntil(() => Promise.resolve(false)); -cy.waitUntil(() => true, {}) -cy.waitUntil(() => false, {}) -cy.waitUntil(() => Promise.resolve(true), {}) -cy.waitUntil(() => Promise.resolve(false), {}) +cy.waitUntil(() => true, {}); +cy.waitUntil(() => false, {}); +cy.waitUntil(() => Promise.resolve(true), {}); +cy.waitUntil(() => Promise.resolve(false), {}); -cy.waitUntil(() => true, { timeout: 500 }) -cy.waitUntil(() => false, { timeout: 500 }) -cy.waitUntil(() => Promise.resolve(true), { timeout: 500 }) -cy.waitUntil(() => Promise.resolve(false), { timeout: 500 }) +cy.waitUntil(() => true, { timeout: 500 }); +cy.waitUntil(() => false, { timeout: 500 }); +cy.waitUntil(() => Promise.resolve(true), { timeout: 500 }); +cy.waitUntil(() => Promise.resolve(false), { timeout: 500 }); -cy.waitUntil(() => true, { errorMsg: "Custom error message" }) -cy.waitUntil(() => false, { errorMsg: "Custom error message" }) -cy.waitUntil(() => Promise.resolve(true), { errorMsg: "Custom error message" }) -cy.waitUntil(() => Promise.resolve(false), { errorMsg: "Custom error message" }) +cy.waitUntil(() => true, { errorMsg: "Custom error message" }); +cy.waitUntil(() => false, { errorMsg: "Custom error message" }); +cy.waitUntil(() => Promise.resolve(true), { errorMsg: "Custom error message" }); +cy.waitUntil(() => Promise.resolve(false), { errorMsg: "Custom error message" }); + +cy.waitUntil(() => true, { description: "Custom description" }); + +cy.waitUntil(() => true, { + logger: ({ name, message, consoleProps }) => { + console.log({ name, message, consoleProps }); + } +}); diff --git a/index.d.ts b/index.d.ts index fe4e432..096c809 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,10 +1,20 @@ /// +type WaitUntilLog = Pick; + +interface WaitUntilOptions { + timeout?: number; + interval?: number; + errorMsg?: string; + description?: string; + logger?: (WaitUntilLog) => any; +} + declare namespace Cypress { interface Chainable { waitUntil( checkFunction: () => Subject | Chainable | Promise, - options?: { timeout?: number; interval?: number; errorMsg?: string } + options?: WaitUntilOptions ): Chainable; } } diff --git a/package.json b/package.json index f39896e..2e53974 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cypress-wait-until", - "version": "1.4.1", + "version": "1.4.2", "description": "A waiting plugin for Cypress", "main": "src/index.js", "dependencies": {}, diff --git a/src/index.js b/src/index.js index 1a8d778..8c6ade2 100644 --- a/src/index.js +++ b/src/index.js @@ -1,41 +1,55 @@ -'use strict' +"use strict"; + +// log generico del comando <- da testaree √ e documentare X + nuova options logger X function waitUntil(subject, checkFunction, options) { if (!(checkFunction instanceof Function)) { - throw new Error('`checkFunction` parameter should be a function. Found: ' + checkFunction) + throw new Error("`checkFunction` parameter should be a function. Found: " + checkFunction); } - options = options || {} + options = options || {}; + + const TIMEOUT_INTERVAL = options.interval || 200; + const TIMEOUT = options.timeout || 5000; + const ERROR_MSG = options.errorMsg || "Timed out retrying"; + const LOG_DESCRIPTION = options.description || "waitUntil"; + let retries = Math.floor(TIMEOUT / TIMEOUT_INTERVAL); - const TIMEOUT_INTERVAL = options.interval || 200 - const TIMEOUT = options.timeout || 5000 - const ERROR_MSG = options.errorMsg || 'Timed out retrying' - let retries = Math.floor(TIMEOUT / TIMEOUT_INTERVAL) + const logger = options.logger || Cypress.log; + + logger({ + name: LOG_DESCRIPTION, + message: options, + consoleProps: () => ({ + options + }) + }); const check = result => { if (result) { - return result + return result; } if (retries < 1) { - throw new Error(ERROR_MSG) + throw new Error(ERROR_MSG); } - cy.wait(TIMEOUT_INTERVAL).then(() => { - retries-- - return resolveValue() - }) - } + cy.wait(TIMEOUT_INTERVAL, { log: false }).then(() => { + retries--; + return resolveValue(); + }); + }; const resolveValue = () => { - const result = checkFunction(subject) - const isAPromise = Boolean(result && result.then) + const result = checkFunction(subject); + + const isAPromise = Boolean(result && result.then); if (isAPromise) { - return result.then(check) + return result.then(check); } else { - return check(result) + return check(result); } - } + }; - return resolveValue() + return resolveValue(); } -Cypress.Commands.add("waitUntil", {prevSubject:'optional'}, waitUntil); +Cypress.Commands.add("waitUntil", { prevSubject: "optional" }, waitUntil); From 40a769ac644009b6e4698b81048012a9f166c3ba Mon Sep 17 00:00:00 2001 From: Stefano Magni Date: Wed, 30 Oct 2019 15:20:41 +0100 Subject: [PATCH 2/2] =?UTF-8?q?chore:=20=F0=9F=A4=96=20Add=20Semantic=20Re?= =?UTF-8?q?lease?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .travis.yml | 1 + README.md | 3 +-- package.json | 7 +++++-- release.config.js | 7 +++++++ 4 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 release.config.js diff --git a/.travis.yml b/.travis.yml index 850f802..0741aa5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,3 +23,4 @@ script: - fossa analyze after_success: - cd && fossa test + - npm run semantic-release diff --git a/README.md b/README.md index 793a305..49c706f 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,7 @@ Add the Cypress waiting power to virtually everything 🎉 [![NPM downloads](https://img.shields.io/npm/dw/cypress-wait-until?color=CB3836)](https://www.npmjs.com/package/cypress-wait-until)
[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/) -[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2FNoriSte%2Fcypress-wait-until.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2FNoriSte%2Fcypress-wait-until?ref=badge_shield) -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2FNoriSte%2Fcypress-wait-until.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2FNoriSte%2Fcypress-wait-until?ref=badge_shield) [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![TypeScript](https://badges.frapsoft.com/typescript/love/typescript.svg?v=101)](https://github.com/ellerbrock/typescript-badges/) [![Open Source Saturday](https://img.shields.io/badge/%E2%9D%A4%EF%B8%8F-open%20source%20saturday-F64060.svg)](https://www.meetup.com/it-IT/Open-Source-Saturday-Milano/) diff --git a/package.json b/package.json index 2e53974..0334bac 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,9 @@ "git-cz": "3.3.0", "serve": "11.2.0", "start-server-and-test": "1.10.6", - "typescript": "3.6.4" + "typescript": "3.6.4", + "@semantic-release/npm": "5.3.2", + "semantic-release": "15.13.28" }, "types": "index.d.ts", "config": { @@ -25,7 +27,8 @@ "test": "npm run cy:start-server-and-test", "cy:start-server-and-test": "start-server-and-test serve :5000 cy:run", "cy:run": "cypress run", - "typescript": "tsc --project ./tsconfig.json" + "typescript": "tsc --project ./tsconfig.json", + "semantic-release": "semantic-release" }, "repository": { "type": "git", diff --git a/release.config.js b/release.config.js new file mode 100644 index 0000000..8400476 --- /dev/null +++ b/release.config.js @@ -0,0 +1,7 @@ +module.exports = { + plugins: [ + "@semantic-release/release-notes-generator", + "@semantic-release/github", + "@semantic-release/npm" + ] +};