Skip to content

Commit

Permalink
Merge pull request #55 from NoriSte/feature/log-options
Browse files Browse the repository at this point in the history
Add some log options
  • Loading branch information
NoriSte authored Oct 31, 2019
2 parents ed226ef + 50deccc commit 5d3ea58
Show file tree
Hide file tree
Showing 7 changed files with 271 additions and 51 deletions.
22 changes: 15 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,21 @@ 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. |
| `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. |
| 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. |
| `log` | `true` | Enable/disable logging. |
| `customMessage` | `undefined` | String logged after the `options.description`. |
| `verbose` | `false` | If every single check result must be logged. |
| `customCheckMessage` | `undefined` | Like `customMessage`, but used for every single check. Useless if `verbose` is not set to `true`. |

Log options are a lot, take a look at the next screenshot to understand how they are printed

![Plugin log options](assets/log-explained.jpg)

<br />
<br />
Expand Down
Binary file added assets/log-explained.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
114 changes: 109 additions & 5 deletions cypress/integration/plugin.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ context("Cypress Wait Until", () => {
.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)
);
cy.waitUntil(checkFunction).then(() => {
cy.getCookie(COOKIE_NAME).then(cookieValue =>
expect(cookieValue.value).to.be.equal(EXPECTED_COOKIE_VALUE)
);
});
});

it("Should apply options correctly", () => {
Expand Down Expand Up @@ -233,4 +233,108 @@ context("Cypress Wait Until", () => {
expect(lastCallArgs).deep.include({ name: description });
});
});

it("Should accept a custom message", () => {
const checkFunction = () => true;
const customMessage = "custom message";

const logger = {
log: (...params) => Cypress.log(...params)
};
const spy = cy.spy(logger, "log");
const options = { logger: logger.log, customMessage };

cy.waitUntil(checkFunction, options).then(() => {
expect(spy).to.have.been.called;
const lastCallArgs = spy.lastCall.args[0];
expect(lastCallArgs.message).deep.include(customMessage);
});
});

it("Should allow to turn off logging", () => {
const checkFunction = () => true;

const logger = {
log: (...params) => Cypress.log(...params)
};
const spy = cy.spy(logger, "log");

cy.waitUntil(checkFunction, { logger: logger.log, log: false }).then(() => {
expect(spy).not.to.have.been.called;
});
});

it("Should log verbosely every single check", () => {
let checks = 0;
const checkFunction = () => {
checks++;
return checks > 1;
};

const logger = {
log: (...params) => Cypress.log(...params)
};
const spy = cy.spy(logger, "log");
const options = { logger: logger.log, verbose: true };

cy.waitUntil(checkFunction, options).then(() => {
const calls = spy.getCalls();
const expected = [
{
name: "waitUntil"
},
{
name: "waitUntil",
message: "false"
},
{
name: "waitUntil",
message: "true"
}
];
expect(calls).to.have.lengthOf(expected.length);
for (let n = calls.length, i = 0; i < n; i++) {
expect(calls[i].args[0]).deep.include(expected[i]);
}
});
});

it("Should accept a `customCheckMessage` option", () => {
const checkFunction = () => true;

const logger = {
log: (...params) => Cypress.log(...params)
};
const spy = cy.spy(logger, "log");
const customCheckMessage = "custom message check";
const options = { logger: logger.log, verbose: true, customCheckMessage };

cy.waitUntil(checkFunction, options).then(() => {
expect(spy.getCalls()[1].args[0].message.toString()).to.include(customCheckMessage);
});
});

// test useful just to printout all the available options, screenshot them, and add them to the README
it("Options explanation", () => {
let checks = 0;
const checkFunction = () => {
checks++;
return checks > 2;
};
const checkFunction2 = () => {
checks++;
return checks > 5;
};

const options = {
// log options
description: "description",
customMessage: "customMessage",
verbose: true,
customCheckMessage: "customCheckMessage"
};

cy.waitUntil(checkFunction, { verbose: true });
cy.waitUntil(checkFunction2, options);
});
});
106 changes: 90 additions & 16 deletions cypress/types/plugin.spec.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,91 @@
/// <reference types="Cypress" />
cy.waitUntil(function () { return true; });
cy.waitUntil(function () { return false; });
cy.waitUntil(function () { return Promise.resolve(true); });
cy.waitUntil(function () { return Promise.resolve(false); });
cy.waitUntil(function () { return true; }, {});
cy.waitUntil(function () { return false; }, {});
cy.waitUntil(function () { return Promise.resolve(true); }, {});
cy.waitUntil(function () { return Promise.resolve(false); }, {});
cy.waitUntil(function () { return true; }, { timeout: 500 });
cy.waitUntil(function () { return false; }, { timeout: 500 });
cy.waitUntil(function () { return Promise.resolve(true); }, { timeout: 500 });
cy.waitUntil(function () { return Promise.resolve(false); }, { timeout: 500 });
cy.waitUntil(function () { return true; }, { errorMsg: "Custom error message" });
cy.waitUntil(function () { return false; }, { errorMsg: "Custom error message" });
cy.waitUntil(function () { return Promise.resolve(true); }, { errorMsg: "Custom error message" });
cy.waitUntil(function () { return Promise.resolve(false); }, { errorMsg: "Custom error message" });
cy.waitUntil(function() {
return true;
});
cy.waitUntil(function() {
return false;
});
cy.waitUntil(function() {
return Promise.resolve(true);
});
cy.waitUntil(function() {
return Promise.resolve(false);
});
cy.waitUntil(function() {
return true;
}, {});
cy.waitUntil(function() {
return false;
}, {});
cy.waitUntil(function() {
return Promise.resolve(true);
}, {});
cy.waitUntil(function() {
return Promise.resolve(false);
}, {});
cy.waitUntil(
function() {
return true;
},
{ timeout: 500 }
);
cy.waitUntil(
function() {
return false;
},
{ timeout: 500 }
);
cy.waitUntil(
function() {
return Promise.resolve(true);
},
{ timeout: 500 }
);
cy.waitUntil(
function() {
return Promise.resolve(false);
},
{ timeout: 500 }
);
cy.waitUntil(
function() {
return true;
},
{ errorMsg: "Custom error message" }
);
cy.waitUntil(
function() {
return false;
},
{ errorMsg: "Custom error message" }
);
cy.waitUntil(
function() {
return Promise.resolve(true);
},
{ errorMsg: "Custom error message" }
);
cy.waitUntil(
function() {
return 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 });
}
});
cy.waitUntil(() => true, {
log: false
});
cy.waitUntil(() => true, {
customMessage: "custom message"
});
cy.waitUntil(() => true, {
verbose: true
});
cy.waitUntil(() => true, {
customCheckMessage: "custom check message"
});
3 changes: 3 additions & 0 deletions cypress/types/plugin.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,6 @@ cy.waitUntil(() => true, {
console.log({ name, message, consoleProps });
}
});

cy.waitUntil(() => true, { log: false });
cy.waitUntil(() => true, { customMessage: "custom message" });
4 changes: 4 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ interface WaitUntilOptions {
interval?: number;
errorMsg?: string;
description?: string;
customMessage?: string;
verbose?: boolean;
customCheckMessage?: string;
logger?: (WaitUntilLog) => any;
log?: boolean;
}

declare namespace Cypress {
Expand Down
73 changes: 50 additions & 23 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,65 @@
"use strict";

// log generico del comando <- da testaree √ e documentare X + nuova options logger X
const logCommand = ({ options, originalOptions }) => {
if (options.log) {
options.logger({
name: options.description,
message: options.customMessage,
consoleProps: () => originalOptions
});
}
};
const logCommandCheck = ({ result, options, originalOptions }) => {
if (!options.log || !options.verbose) return;

function waitUntil(subject, checkFunction, options) {
const message = [result];
if (options.customCheckMessage) {
message.unshift(options.customCheckMessage);
}
options.logger({
name: options.description,
message,
consoleProps: () => originalOptions
});
};

const waitUntil = (subject, checkFunction, originalOptions = {}) => {
if (!(checkFunction instanceof Function)) {
throw new Error("`checkFunction` parameter should be a function. Found: " + checkFunction);
}
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 logger = options.logger || Cypress.log;

logger({
name: LOG_DESCRIPTION,
message: options,
consoleProps: () => ({
options
})
});

const defaultOptions = {
// base options
interval: 200,
timeout: 5000,
errorMsg: "Timed out retrying",

// log options
description: "waitUntil",
log: true,
customMessage: undefined,
logger: Cypress.log,
verbose: false,
customCheckMessage: undefined
};
const options = { ...defaultOptions, ...originalOptions };

// filter out a falsy passed "customMessage" value
options.customMessage = [options.customMessage, originalOptions].filter(Boolean);

let retries = Math.floor(options.timeout / options.interval);

logCommand({ options, originalOptions });

const check = result => {
logCommandCheck({ result, options, originalOptions });
if (result) {
return result;
}
if (retries < 1) {
throw new Error(ERROR_MSG);
throw new Error(options.errorMsg);
}
cy.wait(TIMEOUT_INTERVAL, { log: false }).then(() => {
cy.wait(options.interval, { log: false }).then(() => {
retries--;
return resolveValue();
});
Expand All @@ -41,7 +69,6 @@ function waitUntil(subject, checkFunction, options) {
const result = checkFunction(subject);

const isAPromise = Boolean(result && result.then);

if (isAPromise) {
return result.then(check);
} else {
Expand All @@ -50,6 +77,6 @@ function waitUntil(subject, checkFunction, options) {
};

return resolveValue();
}
};

Cypress.Commands.add("waitUntil", { prevSubject: "optional" }, waitUntil);

0 comments on commit 5d3ea58

Please sign in to comment.