Skip to content
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

Internal Cypress.log management #54

Merged
merged 2 commits into from
Oct 30, 2019
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
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ script:
- fossa analyze
after_success:
- cd <SOURCE_DIR> && fossa test
- npm run semantic-release
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
<br />
[![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/)
Expand Down Expand Up @@ -128,11 +127,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. |

<br />
<br />
Expand Down
255 changes: 162 additions & 93 deletions cypress/integration/plugin.spec.js
Original file line number Diff line number Diff line change
@@ -1,167 +1,236 @@
/// <reference types="Cypress" />

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;

const checkFunction = () => {
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 });
});
});
});
Loading