From 573c503ab3b3d901489fdaecd279694d94402f6f Mon Sep 17 00:00:00 2001 From: decaffeinate Date: Wed, 13 May 2020 14:50:42 +0900 Subject: [PATCH 1/3] decaffeinate: Rename check_spec.coffee and 9 other files from .coffee to .js decaffeinate: Rename trigger_spec.coffee from .coffee to .js --- .../commands/actions/{check_spec.coffee => check_spec.js} | 0 .../commands/actions/{focus_spec.coffee => focus_spec.js} | 0 .../commands/actions/{hover_spec.coffee => hover_spec.js} | 0 .../commands/actions/{scroll_spec.coffee => scroll_spec.js} | 0 .../commands/actions/{select_spec.coffee => select_spec.js} | 0 .../commands/actions/{submit_spec.coffee => submit_spec.js} | 0 .../commands/actions/{trigger_spec.coffee => trigger_spec.js} | 0 .../integration/commands/{agents_spec.coffee => agents_spec.js} | 0 .../commands/{aliasing_spec.coffee => aliasing_spec.js} | 0 .../integration/commands/{angular_spec.coffee => angular_spec.js} | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename packages/driver/test/cypress/integration/commands/actions/{check_spec.coffee => check_spec.js} (100%) rename packages/driver/test/cypress/integration/commands/actions/{focus_spec.coffee => focus_spec.js} (100%) rename packages/driver/test/cypress/integration/commands/actions/{hover_spec.coffee => hover_spec.js} (100%) rename packages/driver/test/cypress/integration/commands/actions/{scroll_spec.coffee => scroll_spec.js} (100%) rename packages/driver/test/cypress/integration/commands/actions/{select_spec.coffee => select_spec.js} (100%) rename packages/driver/test/cypress/integration/commands/actions/{submit_spec.coffee => submit_spec.js} (100%) rename packages/driver/test/cypress/integration/commands/actions/{trigger_spec.coffee => trigger_spec.js} (100%) rename packages/driver/test/cypress/integration/commands/{agents_spec.coffee => agents_spec.js} (100%) rename packages/driver/test/cypress/integration/commands/{aliasing_spec.coffee => aliasing_spec.js} (100%) rename packages/driver/test/cypress/integration/commands/{angular_spec.coffee => angular_spec.js} (100%) diff --git a/packages/driver/test/cypress/integration/commands/actions/check_spec.coffee b/packages/driver/test/cypress/integration/commands/actions/check_spec.js similarity index 100% rename from packages/driver/test/cypress/integration/commands/actions/check_spec.coffee rename to packages/driver/test/cypress/integration/commands/actions/check_spec.js diff --git a/packages/driver/test/cypress/integration/commands/actions/focus_spec.coffee b/packages/driver/test/cypress/integration/commands/actions/focus_spec.js similarity index 100% rename from packages/driver/test/cypress/integration/commands/actions/focus_spec.coffee rename to packages/driver/test/cypress/integration/commands/actions/focus_spec.js diff --git a/packages/driver/test/cypress/integration/commands/actions/hover_spec.coffee b/packages/driver/test/cypress/integration/commands/actions/hover_spec.js similarity index 100% rename from packages/driver/test/cypress/integration/commands/actions/hover_spec.coffee rename to packages/driver/test/cypress/integration/commands/actions/hover_spec.js diff --git a/packages/driver/test/cypress/integration/commands/actions/scroll_spec.coffee b/packages/driver/test/cypress/integration/commands/actions/scroll_spec.js similarity index 100% rename from packages/driver/test/cypress/integration/commands/actions/scroll_spec.coffee rename to packages/driver/test/cypress/integration/commands/actions/scroll_spec.js diff --git a/packages/driver/test/cypress/integration/commands/actions/select_spec.coffee b/packages/driver/test/cypress/integration/commands/actions/select_spec.js similarity index 100% rename from packages/driver/test/cypress/integration/commands/actions/select_spec.coffee rename to packages/driver/test/cypress/integration/commands/actions/select_spec.js diff --git a/packages/driver/test/cypress/integration/commands/actions/submit_spec.coffee b/packages/driver/test/cypress/integration/commands/actions/submit_spec.js similarity index 100% rename from packages/driver/test/cypress/integration/commands/actions/submit_spec.coffee rename to packages/driver/test/cypress/integration/commands/actions/submit_spec.js diff --git a/packages/driver/test/cypress/integration/commands/actions/trigger_spec.coffee b/packages/driver/test/cypress/integration/commands/actions/trigger_spec.js similarity index 100% rename from packages/driver/test/cypress/integration/commands/actions/trigger_spec.coffee rename to packages/driver/test/cypress/integration/commands/actions/trigger_spec.js diff --git a/packages/driver/test/cypress/integration/commands/agents_spec.coffee b/packages/driver/test/cypress/integration/commands/agents_spec.js similarity index 100% rename from packages/driver/test/cypress/integration/commands/agents_spec.coffee rename to packages/driver/test/cypress/integration/commands/agents_spec.js diff --git a/packages/driver/test/cypress/integration/commands/aliasing_spec.coffee b/packages/driver/test/cypress/integration/commands/aliasing_spec.js similarity index 100% rename from packages/driver/test/cypress/integration/commands/aliasing_spec.coffee rename to packages/driver/test/cypress/integration/commands/aliasing_spec.js diff --git a/packages/driver/test/cypress/integration/commands/angular_spec.coffee b/packages/driver/test/cypress/integration/commands/angular_spec.js similarity index 100% rename from packages/driver/test/cypress/integration/commands/angular_spec.coffee rename to packages/driver/test/cypress/integration/commands/angular_spec.js From a38737b20ac61efb0698aef691f45416726120af Mon Sep 17 00:00:00 2001 From: decaffeinate Date: Wed, 13 May 2020 14:50:45 +0900 Subject: [PATCH 2/3] decaffeinate: Convert check_spec.coffee and 9 other files to JS decaffeinate: Convert trigger_spec.coffee to JS --- .../commands/actions/check_spec.js | 1741 +++++++++-------- .../commands/actions/focus_spec.js | 1252 ++++++------ .../commands/actions/hover_spec.js | 46 +- .../commands/actions/scroll_spec.js | 1614 ++++++++------- .../commands/actions/select_spec.js | 848 ++++---- .../commands/actions/submit_spec.js | 612 +++--- .../commands/actions/trigger_spec.js | 1314 +++++++------ .../integration/commands/agents_spec.js | 1204 +++++++----- .../integration/commands/aliasing_spec.js | 752 +++---- .../integration/commands/angular_spec.js | 481 +++-- 10 files changed, 5401 insertions(+), 4463 deletions(-) diff --git a/packages/driver/test/cypress/integration/commands/actions/check_spec.js b/packages/driver/test/cypress/integration/commands/actions/check_spec.js index 291a69f41072..25998f8f9034 100644 --- a/packages/driver/test/cypress/integration/commands/actions/check_spec.js +++ b/packages/driver/test/cypress/integration/commands/actions/check_spec.js @@ -1,126 +1,134 @@ -$ = Cypress.$.bind(Cypress) -_ = Cypress._ -Promise = Cypress.Promise +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const $ = Cypress.$.bind(Cypress); +const { + _ +} = Cypress; +const { + Promise +} = Cypress; -describe "src/cy/commands/actions/check", -> - before -> - cy - .visit("/fixtures/dom.html") - .then (win) -> - @body = win.document.body.outerHTML +describe("src/cy/commands/actions/check", function() { + before(() => cy + .visit("/fixtures/dom.html") + .then(function(win) { + return this.body = win.document.body.outerHTML; + })); - beforeEach -> - doc = cy.state("document") + beforeEach(function() { + const doc = cy.state("document"); - $(doc.body).empty().html(@body) + return $(doc.body).empty().html(this.body); + }); - context "#check", -> - it "does not change the subject", -> - inputs = $("[name=colors]") + context("#check", function() { + it("does not change the subject", function() { + const inputs = $("[name=colors]"); - cy.get("[name=colors]").check().then ($inputs) -> - expect($inputs.length).to.eq(3) - expect($inputs.toArray()).to.deep.eq(inputs.toArray()) + return cy.get("[name=colors]").check().then(function($inputs) { + expect($inputs.length).to.eq(3); + return expect($inputs.toArray()).to.deep.eq(inputs.toArray()); + }); + }); - it "changes the subject if specific value passed to check", -> - checkboxes = $("[name=colors]") + it("changes the subject if specific value passed to check", function() { + const checkboxes = $("[name=colors]"); - cy.get("[name=colors]").check(["blue", "red"]).then ($chk) -> - expect($chk.length).to.eq(2) + return cy.get("[name=colors]").check(["blue", "red"]).then(function($chk) { + expect($chk.length).to.eq(2); - blue = checkboxes.filter("[value=blue]") - red = checkboxes.filter("[value=red]") + const blue = checkboxes.filter("[value=blue]"); + const red = checkboxes.filter("[value=red]"); - expect($chk.get(0)).to.eq(blue.get(0)) - expect($chk.get(1)).to.eq(red.get(0)) + expect($chk.get(0)).to.eq(blue.get(0)); + return expect($chk.get(1)).to.eq(red.get(0)); + }); + }); - it "filters out values which were not found", -> - checkboxes = $("[name=colors]") + it("filters out values which were not found", function() { + const checkboxes = $("[name=colors]"); - cy.get("[name=colors]").check(["blue", "purple"]).then ($chk) -> - expect($chk.length).to.eq(1) + return cy.get("[name=colors]").check(["blue", "purple"]).then(function($chk) { + expect($chk.length).to.eq(1); - blue = checkboxes.filter("[value=blue]") + const blue = checkboxes.filter("[value=blue]"); - expect($chk.get(0)).to.eq(blue.get(0)) + return expect($chk.get(0)).to.eq(blue.get(0)); + }); + }); - it "changes the subject when matching values even if noop", -> - checked = $("") - $("[name=colors]").parent().append(checked) + it("changes the subject when matching values even if noop", function() { + const checked = $(""); + $("[name=colors]").parent().append(checked); - checkboxes = $("[name=colors]") + const checkboxes = $("[name=colors]"); - cy.get("[name=colors]").check("blue").then ($chk) -> - expect($chk.length).to.eq(2) + return cy.get("[name=colors]").check("blue").then(function($chk) { + expect($chk.length).to.eq(2); - blue = checkboxes.filter("[value=blue]") + const blue = checkboxes.filter("[value=blue]"); - expect($chk.get(0)).to.eq(blue.get(0)) - expect($chk.get(1)).to.eq(blue.get(1)) + expect($chk.get(0)).to.eq(blue.get(0)); + return expect($chk.get(1)).to.eq(blue.get(1)); + }); + }); - it "checks a checkbox", -> - cy.get(":checkbox[name='colors'][value='blue']").check().then ($checkbox) -> - expect($checkbox).to.be.checked + it("checks a checkbox", () => cy.get(":checkbox[name='colors'][value='blue']").check().then($checkbox => expect($checkbox).to.be.checked)); - it "checks a radio", -> - cy.get(":radio[name='gender'][value='male']").check().then ($radio) -> - expect($radio).to.be.checked + it("checks a radio", () => cy.get(":radio[name='gender'][value='male']").check().then($radio => expect($radio).to.be.checked)); - it "is a noop if already checked", -> - checkbox = ":checkbox[name='colors'][value='blue']" + it("is a noop if already checked", function() { + const checkbox = ":checkbox[name='colors'][value='blue']"; - $(checkbox).prop("checked", true) + $(checkbox).prop("checked", true); - $(checkbox).change -> - done("should not fire change event") + $(checkbox).change(() => done("should not fire change event")); - cy.get(checkbox).check() + return cy.get(checkbox).check(); + }); - ## readonly should only be limited to inputs, not checkboxes - it "can check readonly checkboxes", -> - cy.get('#readonly-checkbox').check().then ($checkbox) -> - expect($checkbox).to.be.checked + //# readonly should only be limited to inputs, not checkboxes + it("can check readonly checkboxes", () => cy.get('#readonly-checkbox').check().then($checkbox => expect($checkbox).to.be.checked)); - it "does not require visibility with force: true", -> - checkbox = ":checkbox[name='birds']" - $(checkbox).last().hide() + it("does not require visibility with force: true", function() { + const checkbox = ":checkbox[name='birds']"; + $(checkbox).last().hide(); - cy.get(checkbox).check({force: true}).then ($checkbox) -> - expect($checkbox).to.be.checked + return cy.get(checkbox).check({force: true}).then($checkbox => expect($checkbox).to.be.checked); + }); - it "can check a collection", -> - cy.get("[name=colors]").check().then ($inputs) -> - $inputs.each (i, el) -> - expect($(el)).to.be.checked + it("can check a collection", () => cy.get("[name=colors]").check().then($inputs => $inputs.each((i, el) => expect($(el)).to.be.checked))); - it "can check a specific value from a collection", -> - cy.get("[name=colors]").check("blue").then ($inputs) -> - expect($inputs.filter(":checked").length).to.eq 1 - expect($inputs.filter("[value=blue]")).to.be.checked + it("can check a specific value from a collection", () => cy.get("[name=colors]").check("blue").then(function($inputs) { + expect($inputs.filter(":checked").length).to.eq(1); + return expect($inputs.filter("[value=blue]")).to.be.checked; + })); - it "can check multiple values from a collection", -> - cy.get("[name=colors]").check(["blue", "green"]).then ($inputs) -> - expect($inputs.filter(":checked").length).to.eq 2 - expect($inputs.filter("[value=blue],[value=green]")).to.be.checked + it("can check multiple values from a collection", () => cy.get("[name=colors]").check(["blue", "green"]).then(function($inputs) { + expect($inputs.filter(":checked").length).to.eq(2); + return expect($inputs.filter("[value=blue],[value=green]")).to.be.checked; + })); - it "can forcibly click even when being covered by another element", -> - checkbox = $("").attr("id", "checkbox-covered-in-span").prependTo($("body")) - span = $("span on checkbox").css(position: "absolute", left: checkbox.offset().left, top: checkbox.offset().top, padding: 5, display: "inline-block", backgroundColor: "yellow").prependTo($("body")) + it("can forcibly click even when being covered by another element", function() { + const checkbox = $("").attr("id", "checkbox-covered-in-span").prependTo($("body")); + const span = $("span on checkbox").css({position: "absolute", left: checkbox.offset().left, top: checkbox.offset().top, padding: 5, display: "inline-block", backgroundColor: "yellow"}).prependTo($("body")); - clicked = false + let clicked = false; - checkbox.on "click", -> - clicked = true + checkbox.on("click", () => clicked = true); - cy.get("#checkbox-covered-in-span").check({force: true}).then -> - expect(clicked).to.be.true + return cy.get("#checkbox-covered-in-span").check({force: true}).then(() => expect(clicked).to.be.true); + }); - it "passes timeout and interval down to click", (done) -> - checkbox = $("") + it("passes timeout and interval down to click", function(done) { + const checkbox = $("") .attr("id", "checkbox-covered-in-span") - .prependTo($("body")) + .prependTo($("body")); - span = $("span on checkbox") + const span = $("span on checkbox") .css({ position: "absolute", left: checkbox.offset().left, @@ -129,755 +137,936 @@ describe "src/cy/commands/actions/check", -> display: "inline-block", backgroundColor: "yellow" }) - .prependTo($("body")) + .prependTo($("body")); - cy.on "command:retry", _.once (options) -> - expect(options.timeout).to.eq 1000 - expect(options.interval).to.eq 60 - done() - - cy.get("#checkbox-covered-in-span").check({timeout: 1000, interval: 60}) - - it "waits until element is no longer disabled", -> - chk = $(":checkbox:first").prop("disabled", true) - - retried = false - clicks = 0 - - chk.on "click", -> - clicks += 1 - - cy.on "command:retry", _.after 3, -> - chk.prop("disabled", false) - retried = true - - cy.get(":checkbox:first").check().then -> - expect(clicks).to.eq(1) - expect(retried).to.be.true - - it "delays 50ms before resolving", -> - cy.$$(":checkbox:first").on "change", (e) => - cy.spy(Promise, "delay") - - cy.get(":checkbox:first").check().then -> - expect(Promise.delay).to.be.calledWith(50, "click") - - describe "assertion verification", -> - beforeEach -> - cy.on "log:added", (attrs, log) => - if log.get("name") is "assert" - @lastLog = log - - return null - - it "eventually passes the assertion", -> - $(":checkbox:first").click -> - _.delay => - $(@).addClass("checked") - , 100 - - cy.get(":checkbox:first").check().should("have.class", "checked").then -> - lastLog = @lastLog - - expect(lastLog.get("name")).to.eq("assert") - expect(lastLog.get("state")).to.eq("passed") - expect(lastLog.get("ended")).to.be.true - - it "eventually passes the assertion on multiple :checkboxs", -> - $(":checkbox").click -> - _.delay => - $(@).addClass("checked") - , 100 - - cy.get(":checkbox").invoke("slice", 0, 2).check().should("have.class", "checked") - - describe "events", -> - it "emits click event", (done) -> - $("[name=colors][value=blue]").click -> done() - cy.get("[name=colors]").check("blue") - - it "emits change event", (done) -> - $("[name=colors][value=blue]").change -> done() - cy.get("[name=colors]").check("blue") - - it "emits focus event", () -> - focus = false - $("[name=colors][value=blue]").focus -> focus = true - cy.get("[name=colors]") - .check("blue") - .then -> expect(focus).to.eq true - - describe "errors", -> - beforeEach -> - Cypress.config("defaultCommandTimeout", 100) - - @logs = [] - - cy.on "log:added", (attrs, log) => - @lastLog = log - @logs.push(log) - - return null - - it "throws when subject isnt dom", (done) -> - cy.on "fail", (err) -> done() - - cy.noop({}).check() - - it "throws when subject is not in the document", (done) -> - checked = 0 - - checkbox = $(":checkbox:first").click (e) -> - checked += 1 - checkbox.remove() - return false - - cy.on "fail", (err) -> - expect(checked).to.eq 1 - expect(err.message).to.include "`cy.check()` failed because this element" - done() - - cy.get(":checkbox:first").check().check() - - it "throws when subject isnt a checkbox or radio", (done) -> - cy.on "fail", (err) -> - expect(err.message).to.include "`cy.check()` can only be called on `:checkbox` and `:radio`. Your subject contains a: `
...
`" - expect(err.docsUrl).to.include("https://on.cypress.io/check") - done() - - ## this will find multiple forms - cy.get("form").check() - - it "throws when any member of the subject isnt a checkbox or radio", (done) -> - cy.on "fail", (err) -> - expect(err.message).to.include "`cy.check()` can only be called on `:checkbox` and `:radio`. Your subject contains a: ``" - expect(err.docsUrl).to.include("https://on.cypress.io/check") - done() - - ## find a textare which should blow up - ## the textarea is the last member of the subject - cy.get(":checkbox,:radio,#comments").check() - - it "throws when any member of the subject isnt visible", (done) -> - chk = $(":checkbox").first().hide() - - cy.on "fail", (err) => - lastLog = @lastLog - - expect(@logs.length).to.eq(chk.length + 1) - expect(lastLog.get("error")).to.eq(err) - expect(err.message).to.include "`cy.check()` failed because this element is not visible" - done() - - cy.get(":checkbox:first").check() - - it "throws when subject is disabled", (done) -> - $(":checkbox:first").prop("disabled", true) - - cy.on "fail", (err) => - ## get + type logs - expect(@logs.length).eq(2) - expect(err.message).to.include("`cy.check()` failed because this element is `disabled`:\n") - done() - - cy.get(":checkbox:first").check() - - it "still ensures visibility even during a noop", (done) -> - chk = $(":checkbox") - chk.show().last().hide() - - cy.on "fail", (err) => - lastLog = @lastLog - - expect(@logs.length).to.eq(chk.length + 1) - expect(lastLog.get("error")).to.eq(err) - expect(err.message).to.include "`cy.check()` failed because this element is not visible" - done() - - cy.get(":checkbox").check() - - it "logs once when not dom subject", (done) -> - cy.on "fail", (err) => - lastLog = @lastLog - - expect(@logs.length).to.eq(1) - expect(lastLog.get("error")).to.eq(err) - done() - - `cy.check()` - - it "throws when input cannot be clicked", (done) -> - checkbox = $("").attr("id", "checkbox-covered-in-span").prependTo($("body")) - span = $("span on button").css(position: "absolute", left: checkbox.offset().left, top: checkbox.offset().top, padding: 5, display: "inline-block", backgroundColor: "yellow").prependTo($("body")) - - cy.on "fail", (err) => - expect(@logs.length).to.eq(2) - expect(err.message).to.include "`cy.check()` failed because this element" - expect(err.message).to.include "is being covered by another element" - done() - - cy.get("#checkbox-covered-in-span").check() - - it "eventually fails the assertion", (done) -> - cy.on "fail", (err) => - lastLog = @lastLog - - expect(err.message).to.include(lastLog.get("error").message) - expect(err.message).not.to.include("undefined") - expect(lastLog.get("name")).to.eq("assert") - expect(lastLog.get("state")).to.eq("failed") - - expect(lastLog.get("error")).to.be.an.instanceof(chai.AssertionError) - - done() - - cy.get(":checkbox:first").check().should("have.class", "checked") - - it "does not log an additional log on failure", (done) -> - cy.on "fail", => - expect(@logs.length).to.eq(3) - done() - - cy.get(":checkbox:first").check().should("have.class", "checked") - - describe ".log", -> - beforeEach -> - cy.on "log:added", (attrs, log) => - @lastLog = log - - return null - - it "logs immediately before resolving", (done) -> - chk = $(":checkbox:first") - - cy.on "log:added", (attrs, log) -> - if log.get("name") is "check" - expect(log.get("state")).to.eq("pending") - expect(log.get("$el").get(0)).to.eq chk.get(0) - done() - - cy.get(":checkbox:first").check() - - it "snapshots before clicking", (done) -> - $(":checkbox:first").change => - lastLog = @lastLog - - expect(lastLog.get("snapshots").length).to.eq(1) - expect(lastLog.get("snapshots")[0].name).to.eq("before") - expect(lastLog.get("snapshots")[0].body).to.be.an("object") - done() - - cy.get(":checkbox:first").check() - - it "snapshots after clicking", -> - cy.get(":checkbox:first").check().then -> - lastLog = @lastLog - - expect(lastLog.get("snapshots").length).to.eq(2) - expect(lastLog.get("snapshots")[1].name).to.eq("after") - expect(lastLog.get("snapshots")[1].body).to.be.an("object") - - it "logs only 1 check event on click of 1 checkbox", -> - logs = [] - checks = [] - - cy.on "log:added", (attrs, log) -> - logs.push(log) - checks.push(log) if log.get("name") is "check" - - cy.get("[name=colors][value=blue]").check().then -> - expect(logs.length).to.eq(2) - expect(checks).to.have.length(1) - - it "logs only 1 check event on click of 1 radio", -> - logs = [] - radios = [] - - cy.on "log:added", (attrs, log) -> - logs.push(log) - radios.push(log) if log.get("name") is "check" - - cy.get("[name=gender][value=female]").check().then -> - expect(logs.length).to.eq(2) - expect(radios).to.have.length(1) - - it "logs only 1 check event on checkbox with 1 matching value arg", -> - logs = [] - checks = [] - - cy.on "log:added", (attrs, log) -> - logs.push(log) - checks.push(log) if log.get("name") is "check" - - cy.get("[name=colors]").check("blue").then -> - expect(logs.length).to.eq(2) - expect(checks).to.have.length(1) - - it "logs only 1 check event on radio with 1 matching value arg", -> - logs = [] - radios = [] - - cy.on "log:added", (attrs, log) -> - logs.push(log) - radios.push(log) if log.get("name") is "check" - - cy.get("[name=gender]").check("female").then -> - expect(logs.length).to.eq(2) - expect(radios).to.have.length(1) + cy.on("command:retry", _.once(function(options) { + expect(options.timeout).to.eq(1000); + expect(options.interval).to.eq(60); + return done(); + }) + ); - it "passes in $el", -> - cy.get("[name=colors][value=blue]").check().then ($input) -> - lastLog = @lastLog + return cy.get("#checkbox-covered-in-span").check({timeout: 1000, interval: 60}); + }); - expect(lastLog.get("$el").get(0)).to.eq $input.get(0) + it("waits until element is no longer disabled", function() { + const chk = $(":checkbox:first").prop("disabled", true); - it "passes in coords", -> - cy.get("[name=colors][value=blue]").check().then ($input) -> - lastLog = @lastLog - { fromElWindow }= Cypress.dom.getElementCoordinatesByPosition($input) - expect(lastLog.get("coords")).to.deep.eq(fromElWindow) + let retried = false; + let clicks = 0; - it "ends command when checkbox is already checked", -> - cy.get("[name=colors][value=blue]").check().check().then -> - lastLog = @lastLog - - expect(lastLog.get("state")).eq("passed") - - it "#consoleProps", -> - cy.get("[name=colors][value=blue]").check().then ($input) -> - lastLog = @lastLog - - { fromElWindow }= Cypress.dom.getElementCoordinatesByPosition($input) - console = lastLog.invoke("consoleProps") - expect(console.Command).to.eq "check" - expect(console["Applied To"]).to.eq lastLog.get("$el").get(0) - expect(console.Elements).to.eq 1 - expect(console.Coords).to.deep.eq( - _.pick(fromElWindow, "x", "y") - ) + chk.on("click", () => clicks += 1); - it "#consoleProps when checkbox is already checked", -> - cy.get("[name=colors][value=blue]").invoke("prop", "checked", true).check().then ($input) -> - lastLog = @lastLog - - expect(lastLog.get("coords")).to.be.undefined - expect(lastLog.invoke("consoleProps")).to.deep.eq { - Command: "check" - "Applied To": lastLog.get("$el").get(0) - Elements: 1 - Note: "This checkbox was already checked. No operation took place." - Options: undefined + cy.on("command:retry", _.after(3, function() { + chk.prop("disabled", false); + return retried = true; + }) + ); + + return cy.get(":checkbox:first").check().then(function() { + expect(clicks).to.eq(1); + return expect(retried).to.be.true; + }); + }); + + it("delays 50ms before resolving", function() { + cy.$$(":checkbox:first").on("change", e => { + return cy.spy(Promise, "delay"); + }); + + return cy.get(":checkbox:first").check().then(() => expect(Promise.delay).to.be.calledWith(50, "click")); + }); + + describe("assertion verification", function() { + beforeEach(function() { + cy.on("log:added", (attrs, log) => { + if (log.get("name") === "assert") { + return this.lastLog = log; } + }); - it "#consoleProps when radio is already checked", -> - cy.get("[name=gender][value=male]").check().check().then ($input) -> - lastLog = @lastLog + return null; + }); - expect(lastLog.get("coords")).to.be.undefined - expect(lastLog.invoke("consoleProps")).to.deep.eq { - Command: "check" - "Applied To": lastLog.get("$el").get(0) - Elements: 1 - Note: "This radio was already checked. No operation took place." - Options: undefined + it("eventually passes the assertion", function() { + $(":checkbox:first").click(function() { + return _.delay(() => { + return $(this).addClass("checked"); } - - it "#consoleProps when checkbox with value is already checked", -> - $("[name=colors][value=blue]").prop("checked", true) - - cy.get("[name=colors]").check("blue").then ($input) -> - lastLog = @lastLog - - expect(lastLog.get("coords")).to.be.undefined - expect(lastLog.invoke("consoleProps")).to.deep.eq { - Command: "check" - "Applied To": lastLog.get("$el").get(0) - Elements: 1 - Note: "This checkbox was already checked. No operation took place." - Options: undefined + , 100); + }); + + return cy.get(":checkbox:first").check().should("have.class", "checked").then(function() { + const { + lastLog + } = this; + + expect(lastLog.get("name")).to.eq("assert"); + expect(lastLog.get("state")).to.eq("passed"); + return expect(lastLog.get("ended")).to.be.true; + }); + }); + + return it("eventually passes the assertion on multiple :checkboxs", function() { + $(":checkbox").click(function() { + return _.delay(() => { + return $(this).addClass("checked"); } + , 100); + }); + + return cy.get(":checkbox").invoke("slice", 0, 2).check().should("have.class", "checked"); + }); + }); + + describe("events", function() { + it("emits click event", function(done) { + $("[name=colors][value=blue]").click(() => done()); + return cy.get("[name=colors]").check("blue"); + }); + + it("emits change event", function(done) { + $("[name=colors][value=blue]").change(() => done()); + return cy.get("[name=colors]").check("blue"); + }); + + return it("emits focus event", function() { + let focus = false; + $("[name=colors][value=blue]").focus(() => focus = true); + return cy.get("[name=colors]") + .check("blue") + .then(() => expect(focus).to.eq(true)); + }); + }); + + describe("errors", function() { + beforeEach(function() { + Cypress.config("defaultCommandTimeout", 100); + + this.logs = []; + + cy.on("log:added", (attrs, log) => { + this.lastLog = log; + return this.logs.push(log); + }); + + return null; + }); + + it("throws when subject isnt dom", function(done) { + cy.on("fail", err => done()); + + return cy.noop({}).check(); + }); + + it("throws when subject is not in the document", function(done) { + let checked = 0; + + var checkbox = $(":checkbox:first").click(function(e) { + checked += 1; + checkbox.remove(); + return false; + }); + + cy.on("fail", function(err) { + expect(checked).to.eq(1); + expect(err.message).to.include("`cy.check()` failed because this element"); + return done(); + }); + + return cy.get(":checkbox:first").check().check(); + }); + + it("throws when subject isnt a checkbox or radio", function(done) { + cy.on("fail", function(err) { + expect(err.message).to.include("`cy.check()` can only be called on `:checkbox` and `:radio`. Your subject contains a: `
...
`"); + expect(err.docsUrl).to.include("https://on.cypress.io/check"); + return done(); + }); + + //# this will find multiple forms + return cy.get("form").check(); + }); + + it("throws when any member of the subject isnt a checkbox or radio", function(done) { + cy.on("fail", function(err) { + expect(err.message).to.include("`cy.check()` can only be called on `:checkbox` and `:radio`. Your subject contains a: ``"); + expect(err.docsUrl).to.include("https://on.cypress.io/check"); + return done(); + }); + + //# find a textare which should blow up + //# the textarea is the last member of the subject + return cy.get(":checkbox,:radio,#comments").check(); + }); + + it("throws when any member of the subject isnt visible", function(done) { + const chk = $(":checkbox").first().hide(); + + cy.on("fail", err => { + const { + lastLog + } = this; + + expect(this.logs.length).to.eq(chk.length + 1); + expect(lastLog.get("error")).to.eq(err); + expect(err.message).to.include("`cy.check()` failed because this element is not visible"); + return done(); + }); + + return cy.get(":checkbox:first").check(); + }); + + it("throws when subject is disabled", function(done) { + $(":checkbox:first").prop("disabled", true); + + cy.on("fail", err => { + //# get + type logs + expect(this.logs.length).eq(2); + expect(err.message).to.include("`cy.check()` failed because this element is `disabled`:\n"); + return done(); + }); + + return cy.get(":checkbox:first").check(); + }); + + it("still ensures visibility even during a noop", function(done) { + const chk = $(":checkbox"); + chk.show().last().hide(); + + cy.on("fail", err => { + const { + lastLog + } = this; + + expect(this.logs.length).to.eq(chk.length + 1); + expect(lastLog.get("error")).to.eq(err); + expect(err.message).to.include("`cy.check()` failed because this element is not visible"); + return done(); + }); + + return cy.get(":checkbox").check(); + }); + + it("logs once when not dom subject", function(done) { + cy.on("fail", err => { + const { + lastLog + } = this; + + expect(this.logs.length).to.eq(1); + expect(lastLog.get("error")).to.eq(err); + return done(); + }); + + return cy.check(); + }); + + it("throws when input cannot be clicked", function(done) { + const checkbox = $("").attr("id", "checkbox-covered-in-span").prependTo($("body")); + const span = $("span on button").css({position: "absolute", left: checkbox.offset().left, top: checkbox.offset().top, padding: 5, display: "inline-block", backgroundColor: "yellow"}).prependTo($("body")); + + cy.on("fail", err => { + expect(this.logs.length).to.eq(2); + expect(err.message).to.include("`cy.check()` failed because this element"); + expect(err.message).to.include("is being covered by another element"); + return done(); + }); + + return cy.get("#checkbox-covered-in-span").check(); + }); + + it("eventually fails the assertion", function(done) { + cy.on("fail", err => { + const { + lastLog + } = this; + + expect(err.message).to.include(lastLog.get("error").message); + expect(err.message).not.to.include("undefined"); + expect(lastLog.get("name")).to.eq("assert"); + expect(lastLog.get("state")).to.eq("failed"); + + expect(lastLog.get("error")).to.be.an.instanceof(chai.AssertionError); + + return done(); + }); + + return cy.get(":checkbox:first").check().should("have.class", "checked"); + }); + + return it("does not log an additional log on failure", function(done) { + cy.on("fail", () => { + expect(this.logs.length).to.eq(3); + return done(); + }); + + return cy.get(":checkbox:first").check().should("have.class", "checked"); + }); + }); + + return describe(".log", function() { + beforeEach(function() { + cy.on("log:added", (attrs, log) => { + return this.lastLog = log; + }); + + return null; + }); + + it("logs immediately before resolving", function(done) { + const chk = $(":checkbox:first"); + + cy.on("log:added", function(attrs, log) { + if (log.get("name") === "check") { + expect(log.get("state")).to.eq("pending"); + expect(log.get("$el").get(0)).to.eq(chk.get(0)); + return done(); + } + }); + + return cy.get(":checkbox:first").check(); + }); + + it("snapshots before clicking", function(done) { + $(":checkbox:first").change(() => { + const { + lastLog + } = this; + + expect(lastLog.get("snapshots").length).to.eq(1); + expect(lastLog.get("snapshots")[0].name).to.eq("before"); + expect(lastLog.get("snapshots")[0].body).to.be.an("object"); + return done(); + }); + + return cy.get(":checkbox:first").check(); + }); + + it("snapshots after clicking", () => cy.get(":checkbox:first").check().then(function() { + const { + lastLog + } = this; + + expect(lastLog.get("snapshots").length).to.eq(2); + expect(lastLog.get("snapshots")[1].name).to.eq("after"); + return expect(lastLog.get("snapshots")[1].body).to.be.an("object"); + })); + + it("logs only 1 check event on click of 1 checkbox", function() { + const logs = []; + const checks = []; + + cy.on("log:added", function(attrs, log) { + logs.push(log); + if (log.get("name") === "check") { return checks.push(log); } + }); + + return cy.get("[name=colors][value=blue]").check().then(function() { + expect(logs.length).to.eq(2); + return expect(checks).to.have.length(1); + }); + }); + + it("logs only 1 check event on click of 1 radio", function() { + const logs = []; + const radios = []; + + cy.on("log:added", function(attrs, log) { + logs.push(log); + if (log.get("name") === "check") { return radios.push(log); } + }); + + return cy.get("[name=gender][value=female]").check().then(function() { + expect(logs.length).to.eq(2); + return expect(radios).to.have.length(1); + }); + }); + + it("logs only 1 check event on checkbox with 1 matching value arg", function() { + const logs = []; + const checks = []; + + cy.on("log:added", function(attrs, log) { + logs.push(log); + if (log.get("name") === "check") { return checks.push(log); } + }); + + return cy.get("[name=colors]").check("blue").then(function() { + expect(logs.length).to.eq(2); + return expect(checks).to.have.length(1); + }); + }); + + it("logs only 1 check event on radio with 1 matching value arg", function() { + const logs = []; + const radios = []; + + cy.on("log:added", function(attrs, log) { + logs.push(log); + if (log.get("name") === "check") { return radios.push(log); } + }); + + return cy.get("[name=gender]").check("female").then(function() { + expect(logs.length).to.eq(2); + return expect(radios).to.have.length(1); + }); + }); + + it("passes in $el", () => cy.get("[name=colors][value=blue]").check().then(function($input) { + const { + lastLog + } = this; + + return expect(lastLog.get("$el").get(0)).to.eq($input.get(0)); + })); + + it("passes in coords", () => cy.get("[name=colors][value=blue]").check().then(function($input) { + const { + lastLog + } = this; + const { fromElWindow }= Cypress.dom.getElementCoordinatesByPosition($input); + return expect(lastLog.get("coords")).to.deep.eq(fromElWindow); + })); + + it("ends command when checkbox is already checked", () => cy.get("[name=colors][value=blue]").check().check().then(function() { + const { + lastLog + } = this; + + return expect(lastLog.get("state")).eq("passed"); + })); + + it("#consoleProps", () => cy.get("[name=colors][value=blue]").check().then(function($input) { + const { + lastLog + } = this; + + const { fromElWindow }= Cypress.dom.getElementCoordinatesByPosition($input); + const console = lastLog.invoke("consoleProps"); + expect(console.Command).to.eq("check"); + expect(console["Applied To"]).to.eq(lastLog.get("$el").get(0)); + expect(console.Elements).to.eq(1); + return expect(console.Coords).to.deep.eq( + _.pick(fromElWindow, "x", "y") + ); + })); + + it("#consoleProps when checkbox is already checked", () => cy.get("[name=colors][value=blue]").invoke("prop", "checked", true).check().then(function($input) { + const { + lastLog + } = this; + + expect(lastLog.get("coords")).to.be.undefined; + return expect(lastLog.invoke("consoleProps")).to.deep.eq({ + Command: "check", + "Applied To": lastLog.get("$el").get(0), + Elements: 1, + Note: "This checkbox was already checked. No operation took place.", + Options: undefined + });})); + + it("#consoleProps when radio is already checked", () => cy.get("[name=gender][value=male]").check().check().then(function($input) { + const { + lastLog + } = this; + + expect(lastLog.get("coords")).to.be.undefined; + return expect(lastLog.invoke("consoleProps")).to.deep.eq({ + Command: "check", + "Applied To": lastLog.get("$el").get(0), + Elements: 1, + Note: "This radio was already checked. No operation took place.", + Options: undefined + });})); + + it("#consoleProps when checkbox with value is already checked", function() { + $("[name=colors][value=blue]").prop("checked", true); + + return cy.get("[name=colors]").check("blue").then(function($input) { + const { + lastLog + } = this; + + expect(lastLog.get("coords")).to.be.undefined; + return expect(lastLog.invoke("consoleProps")).to.deep.eq({ + Command: "check", + "Applied To": lastLog.get("$el").get(0), + Elements: 1, + Note: "This checkbox was already checked. No operation took place.", + Options: undefined + });}); + }); - it "logs deltaOptions", -> - cy.get("[name=colors][value=blue]").check({force: true, timeout: 1000}).then -> - lastLog = @lastLog - - expect(lastLog.get("message")).to.eq "{force: true, timeout: 1000}" - expect(lastLog.invoke("consoleProps").Options).to.deep.eq {force: true, timeout: 1000} - - context "#uncheck", -> - it "does not change the subject", -> - inputs = $("[name=birds]") - - cy.get("[name=birds]").uncheck().then ($inputs) -> - expect($inputs.length).to.eq(2) - expect($inputs.toArray()).to.deep.eq(inputs.toArray()) - - it "changes the subject if specific value passed to check", -> - checkboxes = $("[name=birds]") - - cy.get("[name=birds]").check(["cockatoo", "amazon"]).then ($chk) -> - expect($chk.length).to.eq(2) - - cockatoo = checkboxes.filter("[value=cockatoo]") - amazon = checkboxes.filter("[value=amazon]") - - expect($chk.get(0)).to.eq(cockatoo.get(0)) - expect($chk.get(1)).to.eq(amazon.get(0)) - - it "filters out values which were not found", -> - checkboxes = $("[name=birds]") - - cy.get("[name=birds]").check(["cockatoo", "parrot"]).then ($chk) -> - expect($chk.length).to.eq(1) - - cockatoo = checkboxes.filter("[value=cockatoo]") - - expect($chk.get(0)).to.eq(cockatoo.get(0)) - - it "changes the subject when matching values even if noop", -> - checked = $("") - $("[name=birds]").parent().append(checked) - - checkboxes = $("[name=birds]") - - cy.get("[name=birds]").check("cockatoo").then ($chk) -> - expect($chk.length).to.eq(2) - - cockatoo = checkboxes.filter("[value=cockatoo]") - - expect($chk.get(0)).to.eq(cockatoo.get(0)) - expect($chk.get(1)).to.eq(cockatoo.get(1)) - - it "unchecks a checkbox", -> - cy.get("[name=birds][value=cockatoo]").uncheck().then ($checkbox) -> - expect($checkbox).not.to.be.checked - - it "unchecks a checkbox by value", -> - cy.get("[name=birds]").uncheck("cockatoo").then ($checkbox) -> - expect($checkbox.filter(":checked").length).to.eq 0 - expect($checkbox.filter("[value=cockatoo]")).not.to.be.checked + return it("logs deltaOptions", () => cy.get("[name=colors][value=blue]").check({force: true, timeout: 1000}).then(function() { + const { + lastLog + } = this; - it "unchecks multiple checkboxes by values", -> - cy.get("[name=birds]").uncheck(["cockatoo", "amazon"]).then ($checkboxes) -> - expect($checkboxes.filter(":checked").length).to.eq 0 - expect($checkboxes.filter("[value=cockatoo],[value=amazon]")).not.to.be.checked + expect(lastLog.get("message")).to.eq("{force: true, timeout: 1000}"); + return expect(lastLog.invoke("consoleProps").Options).to.deep.eq({force: true, timeout: 1000});})); + }); +}); - it "is a noop if already unchecked", -> - checked = false - checkbox = "[name=birds][value=cockatoo]" + return context("#uncheck", function() { + it("does not change the subject", function() { + const inputs = $("[name=birds]"); - $(checkbox).prop("checked", false).change -> - checked = true + return cy.get("[name=birds]").uncheck().then(function($inputs) { + expect($inputs.length).to.eq(2); + return expect($inputs.toArray()).to.deep.eq(inputs.toArray()); + }); + }); - cy.get(checkbox).uncheck().then -> - expect(checked).to.be.false + it("changes the subject if specific value passed to check", function() { + const checkboxes = $("[name=birds]"); - it "can forcibly click even when being covered by another element", (done) -> - checkbox = $("").attr("id", "checkbox-covered-in-span").prop("checked", true).prependTo($("body")) - span = $("span on checkbox").css(position: "absolute", left: checkbox.offset().left, top: checkbox.offset().top, padding: 5, display: "inline-block", backgroundColor: "yellow").prependTo($("body")) + return cy.get("[name=birds]").check(["cockatoo", "amazon"]).then(function($chk) { + expect($chk.length).to.eq(2); - checkbox.on "click", -> done() + const cockatoo = checkboxes.filter("[value=cockatoo]"); + const amazon = checkboxes.filter("[value=amazon]"); - cy.get("#checkbox-covered-in-span").uncheck({force: true}) + expect($chk.get(0)).to.eq(cockatoo.get(0)); + return expect($chk.get(1)).to.eq(amazon.get(0)); + }); + }); - it "passes timeout and interval down to click", (done) -> - checkbox = $("").attr("id", "checkbox-covered-in-span").prop("checked", true).prependTo($("body")) - span = $("span on checkbox").css(position: "absolute", left: checkbox.offset().left, top: checkbox.offset().top, padding: 5, display: "inline-block", backgroundColor: "yellow").prependTo($("body")) + it("filters out values which were not found", function() { + const checkboxes = $("[name=birds]"); - cy.on "command:retry", (options) -> - expect(options.timeout).to.eq 1000 - expect(options.interval).to.eq 60 - done() + return cy.get("[name=birds]").check(["cockatoo", "parrot"]).then(function($chk) { + expect($chk.length).to.eq(1); - cy.get("#checkbox-covered-in-span").uncheck({timeout: 1000, interval: 60}) + const cockatoo = checkboxes.filter("[value=cockatoo]"); - it "waits until element is no longer disabled", -> - chk = $(":checkbox:first").prop("checked", true).prop("disabled", true) + return expect($chk.get(0)).to.eq(cockatoo.get(0)); + }); + }); - retried = false - clicks = 0 + it("changes the subject when matching values even if noop", function() { + const checked = $(""); + $("[name=birds]").parent().append(checked); - chk.on "click", -> - clicks += 1 + const checkboxes = $("[name=birds]"); - cy.on "command:retry", _.after 3, -> - chk.prop("disabled", false) - retried = true + return cy.get("[name=birds]").check("cockatoo").then(function($chk) { + expect($chk.length).to.eq(2); - cy.get(":checkbox:first").uncheck().then -> - expect(clicks).to.eq(1) - expect(retried).to.be.true + const cockatoo = checkboxes.filter("[value=cockatoo]"); - describe "assertion verification", -> - beforeEach -> - cy.on "log:added", (attrs, log) => - if log.get("name") is "assert" - @lastLog = log + expect($chk.get(0)).to.eq(cockatoo.get(0)); + return expect($chk.get(1)).to.eq(cockatoo.get(1)); + }); + }); - return null + it("unchecks a checkbox", () => cy.get("[name=birds][value=cockatoo]").uncheck().then($checkbox => expect($checkbox).not.to.be.checked)); - it "eventually passes the assertion", -> - $(":checkbox:first").prop("checked", true).click -> - _.delay => - $(@).addClass("unchecked") - , 100 + it("unchecks a checkbox by value", () => cy.get("[name=birds]").uncheck("cockatoo").then(function($checkbox) { + expect($checkbox.filter(":checked").length).to.eq(0); + return expect($checkbox.filter("[value=cockatoo]")).not.to.be.checked; + })); - cy.get(":checkbox:first").uncheck().should("have.class", "unchecked").then -> - lastLog = @lastLog + it("unchecks multiple checkboxes by values", () => cy.get("[name=birds]").uncheck(["cockatoo", "amazon"]).then(function($checkboxes) { + expect($checkboxes.filter(":checked").length).to.eq(0); + return expect($checkboxes.filter("[value=cockatoo],[value=amazon]")).not.to.be.checked; + })); - expect(lastLog.get("name")).to.eq("assert") - expect(lastLog.get("state")).to.eq("passed") - expect(lastLog.get("ended")).to.be.true + it("is a noop if already unchecked", function() { + let checked = false; + const checkbox = "[name=birds][value=cockatoo]"; - describe "events", -> - it "emits click event", (done) -> - $("[name=colors][value=blue]").prop("checked", true).click -> done() - cy.get("[name=colors]").uncheck("blue") + $(checkbox).prop("checked", false).change(() => checked = true); - it "emits change event", (done) -> - $("[name=colors][value=blue]").prop("checked", true).change -> done() - cy.get("[name=colors]").uncheck("blue") + return cy.get(checkbox).uncheck().then(() => expect(checked).to.be.false); + }); - describe "errors", -> - beforeEach -> - Cypress.config("defaultCommandTimeout", 100) + it("can forcibly click even when being covered by another element", function(done) { + const checkbox = $("").attr("id", "checkbox-covered-in-span").prop("checked", true).prependTo($("body")); + const span = $("span on checkbox").css({position: "absolute", left: checkbox.offset().left, top: checkbox.offset().top, padding: 5, display: "inline-block", backgroundColor: "yellow"}).prependTo($("body")); - @logs = [] + checkbox.on("click", () => done()); - cy.on "log:added", (attrs, log) => - @lastLog = log - @logs.push(log) + return cy.get("#checkbox-covered-in-span").uncheck({force: true}); + }); - return null + it("passes timeout and interval down to click", function(done) { + const checkbox = $("").attr("id", "checkbox-covered-in-span").prop("checked", true).prependTo($("body")); + const span = $("span on checkbox").css({position: "absolute", left: checkbox.offset().left, top: checkbox.offset().top, padding: 5, display: "inline-block", backgroundColor: "yellow"}).prependTo($("body")); - it "throws specifically on a radio", (done) -> - cy.get(":radio").uncheck() + cy.on("command:retry", function(options) { + expect(options.timeout).to.eq(1000); + expect(options.interval).to.eq(60); + return done(); + }); - cy.on "fail", (err) -> - expect(err.message).to.include "`cy.uncheck()` can only be called on `:checkbox`." - expect(err.docsUrl).to.include("https://on.cypress.io/uncheck") - done() + return cy.get("#checkbox-covered-in-span").uncheck({timeout: 1000, interval: 60}); + }); - it "throws if not a checkbox", (done) -> - cy.noop({}).uncheck() + it("waits until element is no longer disabled", function() { + const chk = $(":checkbox:first").prop("checked", true).prop("disabled", true); - cy.on "fail", -> done() + let retried = false; + let clicks = 0; - it "throws when any member of the subject isnt visible", (done) -> - ## grab the first 3 checkboxes. - chk = $(":checkbox").slice(0, 3).show() + chk.on("click", () => clicks += 1); - cy.on "fail", (err) => - lastLog = @lastLog + cy.on("command:retry", _.after(3, function() { + chk.prop("disabled", false); + return retried = true; + }) + ); + + return cy.get(":checkbox:first").uncheck().then(function() { + expect(clicks).to.eq(1); + return expect(retried).to.be.true; + }); + }); + + describe("assertion verification", function() { + beforeEach(function() { + cy.on("log:added", (attrs, log) => { + if (log.get("name") === "assert") { + return this.lastLog = log; + } + }); - len = (chk.length * 2) + 6 - expect(@logs.length).to.eq(len) - expect(lastLog.get("error")).to.eq(err) - expect(err.message).to.include "`cy.uncheck()` failed because this element is not visible" - done() + return null; + }); - cy + return it("eventually passes the assertion", function() { + $(":checkbox:first").prop("checked", true).click(function() { + return _.delay(() => { + return $(this).addClass("unchecked"); + } + , 100); + }); + + return cy.get(":checkbox:first").uncheck().should("have.class", "unchecked").then(function() { + const { + lastLog + } = this; + + expect(lastLog.get("name")).to.eq("assert"); + expect(lastLog.get("state")).to.eq("passed"); + return expect(lastLog.get("ended")).to.be.true; + }); + }); + }); + + describe("events", function() { + it("emits click event", function(done) { + $("[name=colors][value=blue]").prop("checked", true).click(() => done()); + return cy.get("[name=colors]").uncheck("blue"); + }); + + return it("emits change event", function(done) { + $("[name=colors][value=blue]").prop("checked", true).change(() => done()); + return cy.get("[name=colors]").uncheck("blue"); + }); + }); + + describe("errors", function() { + beforeEach(function() { + Cypress.config("defaultCommandTimeout", 100); + + this.logs = []; + + cy.on("log:added", (attrs, log) => { + this.lastLog = log; + return this.logs.push(log); + }); + + return null; + }); + + it("throws specifically on a radio", function(done) { + cy.get(":radio").uncheck(); + + return cy.on("fail", function(err) { + expect(err.message).to.include("`cy.uncheck()` can only be called on `:checkbox`."); + expect(err.docsUrl).to.include("https://on.cypress.io/uncheck"); + return done(); + }); + }); + + it("throws if not a checkbox", function(done) { + cy.noop({}).uncheck(); + + return cy.on("fail", () => done()); + }); + + it("throws when any member of the subject isnt visible", function(done) { + //# grab the first 3 checkboxes. + const chk = $(":checkbox").slice(0, 3).show(); + + cy.on("fail", err => { + const { + lastLog + } = this; + + const len = (chk.length * 2) + 6; + expect(this.logs.length).to.eq(len); + expect(lastLog.get("error")).to.eq(err); + expect(err.message).to.include("`cy.uncheck()` failed because this element is not visible"); + return done(); + }); + + return cy .get(":checkbox").invoke("slice", 0, 3).check().last().invoke("hide") - .get(":checkbox").invoke("slice", 0, 3).uncheck() - - it "logs once when not dom subject", (done) -> - cy.on "fail", (err) => - lastLog = @lastLog - - expect(@logs.length).to.eq(1) - expect(lastLog.get("error")).to.eq(err) - done() - - `cy.uncheck()` - - it "throws when subject is not in the document", (done) -> - unchecked = 0 - - checkbox = $(":checkbox:first").prop("checked", true).click (e) -> - unchecked += 1 - checkbox.prop("checked", true) - checkbox.remove() - return false - - cy.on "fail", (err) -> - expect(unchecked).to.eq 1 - expect(err.message).to.include "`cy.uncheck()` failed because this element" - done() - - cy.get(":checkbox:first").uncheck().uncheck() - - it "throws when input cannot be clicked", (done) -> - checkbox = $("").attr("id", "checkbox-covered-in-span").prop("checked", true).prependTo($("body")) - span = $("span on button").css(position: "absolute", left: checkbox.offset().left, top: checkbox.offset().top, padding: 5, display: "inline-block", backgroundColor: "yellow").prependTo($("body")) - - cy.on "fail", (err) => - expect(@logs.length).to.eq(2) - expect(err.message).to.include "`cy.uncheck()` failed because this element" - expect(err.message).to.include "is being covered by another element" - done() - - cy.get("#checkbox-covered-in-span").uncheck() - - it "throws when subject is disabled", (done) -> - $(":checkbox:first").prop("checked", true).prop("disabled", true) - - cy.on "fail", (err) => - ## get + type logs - expect(@logs.length).eq(2) - expect(err.message).to.include("`cy.uncheck()` failed because this element is `disabled`:\n") - done() - - cy.get(":checkbox:first").uncheck() - - it "eventually passes the assertion on multiple :checkboxs", -> - $(":checkbox").prop("checked", true).click -> - _.delay => - $(@).addClass("unchecked") - , 100 - - cy.get(":checkbox").invoke("slice", 0, 2).uncheck().should("have.class", "unchecked") - - it "eventually fails the assertion", (done) -> - $(":checkbox:first").prop("checked", true) - - cy.on "fail", (err) => - lastLog = @lastLog - - expect(err.message).to.include(lastLog.get("error").message) - expect(err.message).not.to.include("undefined") - expect(lastLog.get("name")).to.eq("assert") - expect(lastLog.get("state")).to.eq("failed") - expect(lastLog.get("error")).to.be.an.instanceof(chai.AssertionError) - - done() - - cy.get(":checkbox:first").uncheck().should("have.class", "unchecked") - - it "does not log an additional log on failure", (done) -> - cy.on "fail", => - expect(@logs.length).to.eq(3) - done() - - cy.get(":checkbox:first").uncheck().should("have.class", "unchecked") - - describe ".log", -> - beforeEach -> - $("[name=colors][value=blue]").prop("checked", true) - - cy.on "log:added", (attrs, log) => - @lastLog = log - - return null - - it "logs immediately before resolving", (done) -> - chk = $(":checkbox:first") - - cy.on "log:added", (attrs, log) -> - if log.get("name") is "uncheck" - expect(log.get("state")).to.eq("pending") - expect(log.get("$el").get(0)).to.eq chk.get(0) - done() - - cy.get(":checkbox:first").check().uncheck() - - it "snapshots before unchecking", (done) -> - $(":checkbox:first").change => - lastLog = @lastLog - - expect(lastLog.get("snapshots").length).to.eq(1) - expect(lastLog.get("snapshots")[0].name).to.eq("before") - expect(lastLog.get("snapshots")[0].body).to.be.an("object") - done() - - cy.get(":checkbox:first").invoke("prop", "checked", true).uncheck() - - it "snapshots after unchecking", -> - cy.get(":checkbox:first").invoke("prop", "checked", true).uncheck().then -> - lastLog = @lastLog - - expect(lastLog.get("snapshots").length).to.eq(2) - expect(lastLog.get("snapshots")[1].name).to.eq("after") - expect(lastLog.get("snapshots")[1].body).to.be.an("object") - - it "logs only 1 uncheck event", -> - logs = [] - unchecks = [] + .get(":checkbox").invoke("slice", 0, 3).uncheck(); + }); + + it("logs once when not dom subject", function(done) { + cy.on("fail", err => { + const { + lastLog + } = this; + + expect(this.logs.length).to.eq(1); + expect(lastLog.get("error")).to.eq(err); + return done(); + }); + + return cy.uncheck(); + }); + + it("throws when subject is not in the document", function(done) { + let unchecked = 0; + + var checkbox = $(":checkbox:first").prop("checked", true).click(function(e) { + unchecked += 1; + checkbox.prop("checked", true); + checkbox.remove(); + return false; + }); + + cy.on("fail", function(err) { + expect(unchecked).to.eq(1); + expect(err.message).to.include("`cy.uncheck()` failed because this element"); + return done(); + }); + + return cy.get(":checkbox:first").uncheck().uncheck(); + }); + + it("throws when input cannot be clicked", function(done) { + const checkbox = $("").attr("id", "checkbox-covered-in-span").prop("checked", true).prependTo($("body")); + const span = $("span on button").css({position: "absolute", left: checkbox.offset().left, top: checkbox.offset().top, padding: 5, display: "inline-block", backgroundColor: "yellow"}).prependTo($("body")); + + cy.on("fail", err => { + expect(this.logs.length).to.eq(2); + expect(err.message).to.include("`cy.uncheck()` failed because this element"); + expect(err.message).to.include("is being covered by another element"); + return done(); + }); + + return cy.get("#checkbox-covered-in-span").uncheck(); + }); + + it("throws when subject is disabled", function(done) { + $(":checkbox:first").prop("checked", true).prop("disabled", true); + + cy.on("fail", err => { + //# get + type logs + expect(this.logs.length).eq(2); + expect(err.message).to.include("`cy.uncheck()` failed because this element is `disabled`:\n"); + return done(); + }); + + return cy.get(":checkbox:first").uncheck(); + }); + + it("eventually passes the assertion on multiple :checkboxs", function() { + $(":checkbox").prop("checked", true).click(function() { + return _.delay(() => { + return $(this).addClass("unchecked"); + } + , 100); + }); - cy.on "log:added", (attrs, log) -> - logs.push(log) - unchecks.push(log) if log.get("name") is "uncheck" + return cy.get(":checkbox").invoke("slice", 0, 2).uncheck().should("have.class", "unchecked"); + }); - cy.get("[name=colors][value=blue]").uncheck().then -> - expect(logs.length).to.eq(2) - expect(unchecks).to.have.length(1) + it("eventually fails the assertion", function(done) { + $(":checkbox:first").prop("checked", true); - it "logs only 1 uncheck event on uncheck with 1 matching value arg", -> - logs = [] - unchecks = [] + cy.on("fail", err => { + const { + lastLog + } = this; - cy.on "log:added", (attrs, log) -> - logs.push(log) - unchecks.push(log) if log.get("name") is "uncheck" + expect(err.message).to.include(lastLog.get("error").message); + expect(err.message).not.to.include("undefined"); + expect(lastLog.get("name")).to.eq("assert"); + expect(lastLog.get("state")).to.eq("failed"); + expect(lastLog.get("error")).to.be.an.instanceof(chai.AssertionError); - cy.get("[name=colors]").uncheck("blue").then -> - expect(logs.length).to.eq(2) - expect(unchecks).to.have.length(1) + return done(); + }); - it "passes in $el", -> - cy.get("[name=colors][value=blue]").uncheck().then ($input) -> - lastLog = @lastLog + return cy.get(":checkbox:first").uncheck().should("have.class", "unchecked"); + }); - expect(lastLog.get("$el").get(0)).to.eq $input.get(0) + return it("does not log an additional log on failure", function(done) { + cy.on("fail", () => { + expect(this.logs.length).to.eq(3); + return done(); + }); - it "ends command when checkbox is already unchecked", -> - cy.get("[name=colors][value=blue]").invoke("prop", "checked", false).uncheck().then -> - lastLog = @lastLog + return cy.get(":checkbox:first").uncheck().should("have.class", "unchecked"); + }); + }); - expect(lastLog.get("state")).eq("passed") + return describe(".log", function() { + beforeEach(function() { + $("[name=colors][value=blue]").prop("checked", true); - it "#consoleProps", -> - cy.get("[name=colors][value=blue]").uncheck().then ($input) -> - lastLog = @lastLog + cy.on("log:added", (attrs, log) => { + return this.lastLog = log; + }); - { fromElWindow } = Cypress.dom.getElementCoordinatesByPosition($input) - console = lastLog.invoke("consoleProps") - expect(console.Command).to.eq "uncheck" - expect(console["Applied To"]).to.eq lastLog.get("$el").get(0) - expect(console.Elements).to.eq(1) - expect(console.Coords).to.deep.eq( - _.pick(fromElWindow, "x", "y") - ) + return null; + }); - it "#consoleProps when checkbox is already unchecked", -> - cy.get("[name=colors][value=blue]").invoke("prop", "checked", false).uncheck().then ($input) -> - lastLog = @lastLog + it("logs immediately before resolving", function(done) { + const chk = $(":checkbox:first"); - expect(lastLog.get("coords")).to.be.undefined - expect(lastLog.invoke("consoleProps")).to.deep.eq { - Command: "uncheck" - "Applied To": lastLog.get("$el").get(0) - Elements: 1 - Note: "This checkbox was already unchecked. No operation took place." - Options: undefined + cy.on("log:added", function(attrs, log) { + if (log.get("name") === "uncheck") { + expect(log.get("state")).to.eq("pending"); + expect(log.get("$el").get(0)).to.eq(chk.get(0)); + return done(); } - - it "#consoleProps when checkbox with value is already unchecked", -> - cy.get("[name=colors][value=blue]").invoke("prop", "checked", false) - cy.get("[name=colors]").uncheck("blue").then ($input) -> - lastLog = @lastLog - - expect(lastLog.get("coords")).to.be.undefined - expect(lastLog.invoke("consoleProps")).to.deep.eq { - Command: "uncheck" - "Applied To": lastLog.get("$el").get(0) - Elements: 1 - Note: "This checkbox was already unchecked. No operation took place." + }); + + return cy.get(":checkbox:first").check().uncheck(); + }); + + it("snapshots before unchecking", function(done) { + $(":checkbox:first").change(() => { + const { + lastLog + } = this; + + expect(lastLog.get("snapshots").length).to.eq(1); + expect(lastLog.get("snapshots")[0].name).to.eq("before"); + expect(lastLog.get("snapshots")[0].body).to.be.an("object"); + return done(); + }); + + return cy.get(":checkbox:first").invoke("prop", "checked", true).uncheck(); + }); + + it("snapshots after unchecking", () => cy.get(":checkbox:first").invoke("prop", "checked", true).uncheck().then(function() { + const { + lastLog + } = this; + + expect(lastLog.get("snapshots").length).to.eq(2); + expect(lastLog.get("snapshots")[1].name).to.eq("after"); + return expect(lastLog.get("snapshots")[1].body).to.be.an("object"); + })); + + it("logs only 1 uncheck event", function() { + const logs = []; + const unchecks = []; + + cy.on("log:added", function(attrs, log) { + logs.push(log); + if (log.get("name") === "uncheck") { return unchecks.push(log); } + }); + + return cy.get("[name=colors][value=blue]").uncheck().then(function() { + expect(logs.length).to.eq(2); + return expect(unchecks).to.have.length(1); + }); + }); + + it("logs only 1 uncheck event on uncheck with 1 matching value arg", function() { + const logs = []; + const unchecks = []; + + cy.on("log:added", function(attrs, log) { + logs.push(log); + if (log.get("name") === "uncheck") { return unchecks.push(log); } + }); + + return cy.get("[name=colors]").uncheck("blue").then(function() { + expect(logs.length).to.eq(2); + return expect(unchecks).to.have.length(1); + }); + }); + + it("passes in $el", () => cy.get("[name=colors][value=blue]").uncheck().then(function($input) { + const { + lastLog + } = this; + + return expect(lastLog.get("$el").get(0)).to.eq($input.get(0)); + })); + + it("ends command when checkbox is already unchecked", () => cy.get("[name=colors][value=blue]").invoke("prop", "checked", false).uncheck().then(function() { + const { + lastLog + } = this; + + return expect(lastLog.get("state")).eq("passed"); + })); + + it("#consoleProps", () => cy.get("[name=colors][value=blue]").uncheck().then(function($input) { + const { + lastLog + } = this; + + const { fromElWindow } = Cypress.dom.getElementCoordinatesByPosition($input); + const console = lastLog.invoke("consoleProps"); + expect(console.Command).to.eq("uncheck"); + expect(console["Applied To"]).to.eq(lastLog.get("$el").get(0)); + expect(console.Elements).to.eq(1); + return expect(console.Coords).to.deep.eq( + _.pick(fromElWindow, "x", "y") + ); + })); + + it("#consoleProps when checkbox is already unchecked", () => cy.get("[name=colors][value=blue]").invoke("prop", "checked", false).uncheck().then(function($input) { + const { + lastLog + } = this; + + expect(lastLog.get("coords")).to.be.undefined; + return expect(lastLog.invoke("consoleProps")).to.deep.eq({ + Command: "uncheck", + "Applied To": lastLog.get("$el").get(0), + Elements: 1, + Note: "This checkbox was already unchecked. No operation took place.", + Options: undefined + });})); + + it("#consoleProps when checkbox with value is already unchecked", function() { + cy.get("[name=colors][value=blue]").invoke("prop", "checked", false); + return cy.get("[name=colors]").uncheck("blue").then(function($input) { + const { + lastLog + } = this; + + expect(lastLog.get("coords")).to.be.undefined; + return expect(lastLog.invoke("consoleProps")).to.deep.eq({ + Command: "uncheck", + "Applied To": lastLog.get("$el").get(0), + Elements: 1, + Note: "This checkbox was already unchecked. No operation took place.", Options: undefined - } - - it "logs deltaOptions", -> - cy.get("[name=colors][value=blue]").check().uncheck({force: true, timeout: 1000}).then -> - lastLog = @lastLog - - expect(lastLog.get("message")).to.eq "{force: true, timeout: 1000}" - expect(lastLog.invoke("consoleProps").Options).to.deep.eq {force: true, timeout: 1000} + });}); + }); + + return it("logs deltaOptions", () => cy.get("[name=colors][value=blue]").check().uncheck({force: true, timeout: 1000}).then(function() { + const { + lastLog + } = this; + + expect(lastLog.get("message")).to.eq("{force: true, timeout: 1000}"); + return expect(lastLog.invoke("consoleProps").Options).to.deep.eq({force: true, timeout: 1000});})); + }); +}); +}); diff --git a/packages/driver/test/cypress/integration/commands/actions/focus_spec.js b/packages/driver/test/cypress/integration/commands/actions/focus_spec.js index a610803a3efd..fcbb11a346c5 100644 --- a/packages/driver/test/cypress/integration/commands/actions/focus_spec.js +++ b/packages/driver/test/cypress/integration/commands/actions/focus_spec.js @@ -1,705 +1,795 @@ -$ = Cypress.$.bind(Cypress) -_ = Cypress._ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const $ = Cypress.$.bind(Cypress); +const { + _ +} = Cypress; -getActiveElement = -> - cy.state("document").activeElement +const getActiveElement = () => cy.state("document").activeElement; -describe "src/cy/commands/actions/focus", -> - before -> - cy - .visit("/fixtures/dom.html") - .then (win) -> - @body = win.document.body.outerHTML +describe("src/cy/commands/actions/focus", function() { + before(() => cy + .visit("/fixtures/dom.html") + .then(function(win) { + return this.body = win.document.body.outerHTML; + })); - beforeEach -> - doc = cy.state("document") + beforeEach(function() { + const doc = cy.state("document"); - $(doc.body).empty().html(@body) + return $(doc.body).empty().html(this.body); + }); - context "#focus", -> - it "sends a focus event", -> - focus = false + context("#focus", function() { + it("sends a focus event", function() { + let focus = false; - cy.$$("#focus input").focus -> - focus = true + cy.$$("#focus input").focus(() => focus = true); - cy.get("#focus input").focus().then ($input) -> - expect(focus).to.be.true - expect(getActiveElement()).to.eq($input.get(0)) + return cy.get("#focus input").focus().then(function($input) { + expect(focus).to.be.true; + return expect(getActiveElement()).to.eq($input.get(0)); + }); + }); - it "bubbles focusin event", -> - focusin = false + it("bubbles focusin event", function() { + let focusin = false; - cy.$$("#focus").focusin -> - focusin = true + cy.$$("#focus").focusin(() => focusin = true); - cy.get("#focus input").focus().then -> - expect(focusin).to.be.true + return cy.get("#focus input").focus().then(() => expect(focusin).to.be.true); + }); - it "manually blurs focused subject as a fallback", -> - blurred = false + it("manually blurs focused subject as a fallback", function() { + let blurred = false; - cy.$$("input:first").blur -> - blurred = true + cy.$$("input:first").blur(() => blurred = true); - cy + return cy .get("input:first").focus() .get("#focus input").focus() - .then -> - expect(blurred).to.be.true + .then(() => expect(blurred).to.be.true); + }); - it "matches cy.focused()", -> - button = cy.$$("#button") + it("matches cy.focused()", function() { + const button = cy.$$("#button"); - cy + return cy .get("#button").focus().focused() - .then ($focused) -> - expect($focused.get(0)).to.eq button.get(0) + .then($focused => expect($focused.get(0)).to.eq(button.get(0))); + }); - it "returns the original subject", -> - button = cy.$$("#button") + it("returns the original subject", function() { + const button = cy.$$("#button"); - cy.get("#button").focus().then ($button) -> - expect($button).to.match button + return cy.get("#button").focus().then($button => expect($button).to.match(button)); + }); - it "causes first focused element to receive blur", -> - blurred = false + it("causes first focused element to receive blur", function() { + let blurred = false; - cy.$$("input:first").blur -> - blurred = true + cy.$$("input:first").blur(() => blurred = true); - cy + return cy .get("input:first").focus() .get("input:last").focus() - .then -> - expect(blurred).to.be.true + .then(() => expect(blurred).to.be.true); + }); - ## https://allyjs.io/data-tables/focusable.html#footnote-3 - ## body is focusable, but it will not steal focus away - ## from another activeElement or cause any focus or blur events - ## to fire - it "can focus the body but does not fire focus or blur events", -> - { body } = doc = cy.state("document") + //# https://allyjs.io/data-tables/focusable.html#footnote-3 + //# body is focusable, but it will not steal focus away + //# from another activeElement or cause any focus or blur events + //# to fire + it("can focus the body but does not fire focus or blur events", function() { + let doc; + const { body } = (doc = cy.state("document")); - focused = false - blurred = false + let focused = false; + let blurred = false; - onFocus = -> - focused = true + const onFocus = () => focused = true; - onBlur = -> - blurred = true + const onBlur = () => blurred = true; - cy - .get("input:first").focus().then ($input) -> - expect(doc.activeElement).to.eq($input.get(0)) + return cy + .get("input:first").focus().then(function($input) { + expect(doc.activeElement).to.eq($input.get(0)); - $input.get(0).addEventListener("blur", onBlur) - body.addEventListener("focus", onFocus) + $input.get(0).addEventListener("blur", onBlur); + body.addEventListener("focus", onFocus); - cy.get("body").focus().then -> - ## should not have changed actual activeElement - expect(doc.activeElement).to.eq($input.get(0)) + return cy.get("body").focus().then(function() { + //# should not have changed actual activeElement + expect(doc.activeElement).to.eq($input.get(0)); - $input.get(0).removeEventListener("blur", onBlur) - body.removeEventListener("focus", onFocus) + $input.get(0).removeEventListener("blur", onBlur); + body.removeEventListener("focus", onFocus); - expect(focused).to.be.false - expect(blurred).to.be.false + expect(focused).to.be.false; + return expect(blurred).to.be.false; + }); + }); + }); - it "can focus the window but does not change activeElement or fire blur events", -> - win = cy.state("window") - doc = cy.state("document") + it("can focus the window but does not change activeElement or fire blur events", function() { + const win = cy.state("window"); + const doc = cy.state("document"); - focused = false - blurred = false + let focused = false; + let blurred = false; - onFocus = -> - focused = true + const onFocus = () => focused = true; - onBlur = -> - blurred = true + const onBlur = () => blurred = true; - cy - .get("input:first").focus().then ($input) -> - expect(doc.activeElement).to.eq($input.get(0)) + return cy + .get("input:first").focus().then(function($input) { + expect(doc.activeElement).to.eq($input.get(0)); - $input.get(0).addEventListener("blur", onBlur) - win.addEventListener("focus", onFocus) + $input.get(0).addEventListener("blur", onBlur); + win.addEventListener("focus", onFocus); - cy.window().focus().then -> - ## should not have changed actual activeElement - expect(doc.activeElement).to.eq($input.get(0)) + return cy.window().focus().then(function() { + //# should not have changed actual activeElement + expect(doc.activeElement).to.eq($input.get(0)); - $input.get(0).removeEventListener("blur", onBlur) - win.removeEventListener("focus", onFocus) + $input.get(0).removeEventListener("blur", onBlur); + win.removeEventListener("focus", onFocus); - expect(focused).to.be.true - expect(blurred).to.be.false + expect(focused).to.be.true; + return expect(blurred).to.be.false; + }); + }); + }); - it "can focus [contenteditable]", -> - ce = cy.$$("[contenteditable]:first") + it("can focus [contenteditable]", function() { + const ce = cy.$$("[contenteditable]:first"); - cy + return cy .get("[contenteditable]:first").focus() - .focused().then ($ce) -> - expect($ce.get(0)).to.eq ce.get(0) - - it "can focus svg elements", -> - onFocus = cy.stub() - - cy.$$("[data-cy=rect]").focus(onFocus) - - cy.get("[data-cy=rect]").focus().then -> - expect(onFocus).to.be.calledOnce - - it "can focus on readonly inputs", -> - onFocus = cy.stub() - - cy.$$("#readonly-attr").focus(onFocus) - - cy.get("#readonly-attr").focus().then -> - expect(onFocus).to.be.calledOnce + .focused().then($ce => expect($ce.get(0)).to.eq(ce.get(0))); + }); - describe "assertion verification", -> - beforeEach -> - cy.on "log:added", (attrs, log) => - if log.get("name") is "assert" - @lastLog = log + it("can focus svg elements", function() { + const onFocus = cy.stub(); - return null + cy.$$("[data-cy=rect]").focus(onFocus); - it "eventually passes the assertion", -> - cy.$$(":text:first").focus -> - _.delay => - $(@).addClass("focused") - , 100 + return cy.get("[data-cy=rect]").focus().then(() => expect(onFocus).to.be.calledOnce); + }); - cy.get(":text:first").focus().should("have.class", "focused").then -> - lastLog = @lastLog + it("can focus on readonly inputs", function() { + const onFocus = cy.stub(); - expect(lastLog.get("name")).to.eq("assert") - expect(lastLog.get("state")).to.eq("passed") - expect(lastLog.get("ended")).to.be.true + cy.$$("#readonly-attr").focus(onFocus); - describe ".log", -> - beforeEach -> - @logs = [] + return cy.get("#readonly-attr").focus().then(() => expect(onFocus).to.be.calledOnce); + }); - cy.on "log:added", (attrs, log) => - if attrs.name is "focus" - @lastLog = log - @logs.push(log) - - return null - - it "logs immediately before resolving", -> - $input = cy.$$(":text:first") - - expected = false - - ## we can't end early here because our focus() - ## command will still be in flight and the promise - ## chain will get canceled before it gets attached - ## (besides the code will continue to run and create - ## side effects) - cy.on "log:added", (attrs, log) -> - if log.get("name") is "focus" - expect(log.get("state")).to.eq("pending") - expect(log.get("$el").get(0)).to.eq $input.get(0) - expected = true - - cy.get(":text:first").focus().then -> - expect(expected).to.be.true - - it "snapshots after clicking", -> - cy.get(":text:first").focus().then -> - lastLog = @lastLog - - expect(lastLog.get("snapshots").length).to.eq(1) - expect(lastLog.get("snapshots")[0]).to.be.an("object") - - it "passes in $el", -> - cy.get("input:first").focus().then ($input) -> - lastLog = @lastLog - - expect(lastLog.get("$el")).to.eq $input - - it "logs 2 focus event", -> - cy - .get("input:first").focus() - .get("button:first").focus().then -> - expect(@logs.length).to.eq(2) - - it "#consoleProps", -> - cy.get("input:first").focus().then ($input) -> - expect(@lastLog.invoke("consoleProps")).to.deep.eq { - Command: "focus" - "Applied To": $input.get(0) + describe("assertion verification", function() { + beforeEach(function() { + cy.on("log:added", (attrs, log) => { + if (log.get("name") === "assert") { + return this.lastLog = log; } + }); - describe "errors", -> - beforeEach -> - Cypress.config("defaultCommandTimeout", 100) + return null; + }); - @logs = [] - - cy.on "log:added", (attrs, log) => - @lastLog = log - @logs.push(log) - - return null - - it "throws when not a dom subject", (done) -> - cy.on "fail", -> done() - - cy.noop({}).focus() - - it "throws when subject is not in the document", (done) -> - focused = 0 + return it("eventually passes the assertion", function() { + cy.$$(":text:first").focus(function() { + return _.delay(() => { + return $(this).addClass("focused"); + } + , 100); + }); + + return cy.get(":text:first").focus().should("have.class", "focused").then(function() { + const { + lastLog + } = this; + + expect(lastLog.get("name")).to.eq("assert"); + expect(lastLog.get("state")).to.eq("passed"); + return expect(lastLog.get("ended")).to.be.true; + }); + }); + }); + + describe(".log", function() { + beforeEach(function() { + this.logs = []; + + cy.on("log:added", (attrs, log) => { + if (attrs.name === "focus") { + this.lastLog = log; + return this.logs.push(log); + } + }); + + return null; + }); + + it("logs immediately before resolving", function() { + const $input = cy.$$(":text:first"); + + let expected = false; + + //# we can't end early here because our focus() + //# command will still be in flight and the promise + //# chain will get canceled before it gets attached + //# (besides the code will continue to run and create + //# side effects) + cy.on("log:added", function(attrs, log) { + if (log.get("name") === "focus") { + expect(log.get("state")).to.eq("pending"); + expect(log.get("$el").get(0)).to.eq($input.get(0)); + return expected = true; + } + }); - $input = cy.$$("input:first").focus (e) -> - focused += 1 - $input.remove() - return false + return cy.get(":text:first").focus().then(() => expect(expected).to.be.true); + }); - cy.on "fail", (err) -> - expect(focused).to.eq 1 - expect(err.message).to.include "`cy.focus()` failed because this element" - done() + it("snapshots after clicking", () => cy.get(":text:first").focus().then(function() { + const { + lastLog + } = this; - cy.get("input:first").focus().focus() + expect(lastLog.get("snapshots").length).to.eq(1); + return expect(lastLog.get("snapshots")[0]).to.be.an("object"); + })); - it "throws when not a[href],link[href],button,input,select,textarea,[tabindex]", (done) -> - cy.on "fail", (err) -> - expect(err.message).to.include "`cy.focus()` can only be called on a valid focusable element. Your subject is a: `
...
`" - expect(err.docsUrl).to.eq("https://on.cypress.io/focus") - done() + it("passes in $el", () => cy.get("input:first").focus().then(function($input) { + const { + lastLog + } = this; - cy.get("form").focus() + return expect(lastLog.get("$el")).to.eq($input); + })); - it "throws when subject is a collection of elements", (done) -> - cy - .get("textarea,:text").then ($inputs) -> - @num = $inputs.length - return $inputs - .focus() - - cy.on "fail", (err) => - expect(err.message).to.include "`cy.focus()` can only be called on a single element. Your subject contained #{@num} elements." - expect(err.docsUrl).to.eq("https://on.cypress.io/focus") - done() - - it "logs once when not dom subject", (done) -> - cy.on "fail", (err) => - lastLog = @lastLog - - expect(@logs.length).to.eq(1) - expect(lastLog.get("error")).to.eq(err) - done() - - cy.focus() - - ## TODO: dont skip this - it.skip "slurps up failed promises", (done) -> - cy.timeout(1000) - - ## we only want to test when the document - ## isnt in focus - if cy.state("document").hasFocus() - return done() - - # now = cy.now - # - # nowFn = (cmd) -> - # ## we stub cy.now so that when we're about to blur - # ## we cause isInDom to return false when its given - # ## the last input element - # if cmd is "blur" - # cy.stub(cy, "isInDom").returns(false) - # - # now.apply(@, arguments) - # - # cy.stub(cy, "now", nowFn) - - $first = cy.$$("input:first") - $last = cy.$$("input:last") - - $first.on "focus", -> - $(@).remove() - - cy.on "fail", (err) -> - expect(err.message).to.include "`cy.blur()` failed because this element" - done() - - ## we remove the first element and then - ## focus on the 2nd. the 2nd focus causes - ## a blur on the 1st element, which should - ## cause an error because its no longer in the DOM + it("logs 2 focus event", () => cy + .get("input:first").focus() + .get("button:first").focus().then(function() { + return expect(this.logs.length).to.eq(2); + })); + + return it("#consoleProps", () => cy.get("input:first").focus().then(function($input) { + return expect(this.lastLog.invoke("consoleProps")).to.deep.eq({ + Command: "focus", + "Applied To": $input.get(0) + });})); + }); + + return describe("errors", function() { + beforeEach(function() { + Cypress.config("defaultCommandTimeout", 100); + + this.logs = []; + + cy.on("log:added", (attrs, log) => { + this.lastLog = log; + return this.logs.push(log); + }); + + return null; + }); + + it("throws when not a dom subject", function(done) { + cy.on("fail", () => done()); + + return cy.noop({}).focus(); + }); + + it("throws when subject is not in the document", function(done) { + let focused = 0; + + var $input = cy.$$("input:first").focus(function(e) { + focused += 1; + $input.remove(); + return false; + }); + + cy.on("fail", function(err) { + expect(focused).to.eq(1); + expect(err.message).to.include("`cy.focus()` failed because this element"); + return done(); + }); + + return cy.get("input:first").focus().focus(); + }); + + it("throws when not a[href],link[href],button,input,select,textarea,[tabindex]", function(done) { + cy.on("fail", function(err) { + expect(err.message).to.include("`cy.focus()` can only be called on a valid focusable element. Your subject is a: `
...
`"); + expect(err.docsUrl).to.eq("https://on.cypress.io/focus"); + return done(); + }); + + return cy.get("form").focus(); + }); + + it("throws when subject is a collection of elements", function(done) { cy + .get("textarea,:text").then(function($inputs) { + this.num = $inputs.length; + return $inputs;}).focus(); + + return cy.on("fail", err => { + expect(err.message).to.include(`\`cy.focus()\` can only be called on a single element. Your subject contained ${this.num} elements.`); + expect(err.docsUrl).to.eq("https://on.cypress.io/focus"); + return done(); + }); + }); + + it("logs once when not dom subject", function(done) { + cy.on("fail", err => { + const { + lastLog + } = this; + + expect(this.logs.length).to.eq(1); + expect(lastLog.get("error")).to.eq(err); + return done(); + }); + + return cy.focus(); + }); + + //# TODO: dont skip this + it.skip("slurps up failed promises", function(done) { + cy.timeout(1000); + + //# we only want to test when the document + //# isnt in focus + if (cy.state("document").hasFocus()) { + return done(); + } + + // now = cy.now + // + // nowFn = (cmd) -> + // ## we stub cy.now so that when we're about to blur + // ## we cause isInDom to return false when its given + // ## the last input element + // if cmd is "blur" + // cy.stub(cy, "isInDom").returns(false) + // + // now.apply(@, arguments) + // + // cy.stub(cy, "now", nowFn) + + const $first = cy.$$("input:first"); + const $last = cy.$$("input:last"); + + $first.on("focus", function() { + return $(this).remove(); + }); + + cy.on("fail", function(err) { + expect(err.message).to.include("`cy.blur()` failed because this element"); + return done(); + }); + + //# we remove the first element and then + //# focus on the 2nd. the 2nd focus causes + //# a blur on the 1st element, which should + //# cause an error because its no longer in the DOM + return cy .get("input:first").focus() .get("input:last").focus() - .then -> - ## sometimes hasFocus() returns false - ## even though its really in focus - ## in those cases, just pass - ## i cant come up with another way - ## to test this accurately - done() + .then(() => //# sometimes hasFocus() returns false + //# even though its really in focus + //# in those cases, just pass + //# i cant come up with another way + //# to test this accurately + done()); + }); - it "eventually fails the assertion", (done) -> - cy.on "fail", (err) => - lastLog = @lastLog + it("eventually fails the assertion", function(done) { + cy.on("fail", err => { + const { + lastLog + } = this; - expect(err.message).to.include(lastLog.get("error").message) - expect(err.message).not.to.include("undefined") - expect(lastLog.get("name")).to.eq("assert") - expect(lastLog.get("state")).to.eq("failed") - expect(lastLog.get("error")).to.be.an.instanceof(chai.AssertionError) + expect(err.message).to.include(lastLog.get("error").message); + expect(err.message).not.to.include("undefined"); + expect(lastLog.get("name")).to.eq("assert"); + expect(lastLog.get("state")).to.eq("failed"); + expect(lastLog.get("error")).to.be.an.instanceof(chai.AssertionError); - done() + return done(); + }); - cy.get(":text:first").focus().should("have.class", "focused") + return cy.get(":text:first").focus().should("have.class", "focused"); + }); - it "does not log an additional log on failure", (done) -> - cy.on "fail", => - expect(@logs.length).to.eq(3) - done() + return it("does not log an additional log on failure", function(done) { + cy.on("fail", () => { + expect(this.logs.length).to.eq(3); + return done(); + }); - cy.get(":text:first").focus().should("have.class", "focused") + return cy.get(":text:first").focus().should("have.class", "focused"); + }); + }); + }); - context "#blur", -> - it "should blur the originally focused element", -> - blurred = false + return context("#blur", function() { + it("should blur the originally focused element", function() { + let blurred = false; - cy.$$("#focus input").blur -> - blurred = true + cy.$$("#focus input").blur(() => blurred = true); - cy.get("#focus").within -> - cy - .get("input").focus() - .then ($input) -> - expect(getActiveElement()).to.eq($input.get(0)) + return cy.get("#focus").within(() => cy + .get("input").focus() + .then($input => expect(getActiveElement()).to.eq($input.get(0))).get("button").focus() + .then(function($btn) { + expect(blurred).to.be.true; + return expect(getActiveElement()).to.eq($btn.get(0)); + })); + }); - .get("button").focus() - .then ($btn) -> - expect(blurred).to.be.true - expect(getActiveElement()).to.eq($btn.get(0)) + it("sends a focusout event", function() { + let focusout = false; - it "sends a focusout event", -> - focusout = false + cy.$$("#focus").focusout(() => focusout = true); - cy.$$("#focus").focusout -> - focusout = true + return cy.get("#focus input").focus().blur().then(() => expect(focusout).to.be.true); + }); - cy.get("#focus input").focus().blur().then -> - expect(focusout).to.be.true + it("sends a blur event", function() { + // cy.$$("input:text:first").get(0).addEventListener "blur", -> done() + let blurred = false; - it "sends a blur event", -> - # cy.$$("input:text:first").get(0).addEventListener "blur", -> done() - blurred = false + cy.$$("input:first").blur(() => blurred = true); - cy.$$("input:first").blur -> - blurred = true + return cy.get("input:first").focus().blur().then(() => expect(blurred).to.be.true); + }); - cy.get("input:first").focus().blur().then -> - expect(blurred).to.be.true + it("returns the original subject", function() { + const input = cy.$$("input:first"); - it "returns the original subject", -> - input = cy.$$("input:first") + return cy.get("input:first").focus().blur().then($input => expect($input).to.match(input)); + }); - cy.get("input:first").focus().blur().then ($input) -> - expect($input).to.match input + it("can blur the body but does not change activeElement or fire blur events", function() { + let doc; + const { body } = (doc = cy.state("document")); - it "can blur the body but does not change activeElement or fire blur events", -> - { body } = doc = cy.state("document") + let blurred = false; - blurred = false + const onBlur = () => blurred = true; - onBlur = -> - blurred = true + body.addEventListener("blur", onBlur); - body.addEventListener("blur", onBlur) + return cy + .get("body").blur().then(() => expect(blurred).to.be.false).get("input:first").focus().then($input => cy + .get("body").blur({ force: true }) + .then(function() { + expect(doc.activeElement).to.eq($input.get(0)); + body.removeEventListener("blur", onBlur); - cy - .get("body").blur().then -> - expect(blurred).to.be.false - .get("input:first").focus().then ($input) -> - cy - .get("body").blur({ force: true }) - .then -> - expect(doc.activeElement).to.eq($input.get(0)) - body.removeEventListener("blur", onBlur) - - expect(blurred).to.be.false + return expect(blurred).to.be.false; + })); + }); - it "can blur the window but does not change activeElement", -> - win = cy.state("window") - doc = cy.state("document") + it("can blur the window but does not change activeElement", function() { + const win = cy.state("window"); + const doc = cy.state("document"); - blurred = false + let blurred = false; - onBlur = -> - blurred = true + const onBlur = () => blurred = true; - win.addEventListener("blur", onBlur) + win.addEventListener("blur", onBlur); - cy - .window().blur().then -> - expect(blurred).to.be.true - .get("input:first").focus().then ($input) -> - cy - .window().blur({ force: true }) - .then -> - expect(doc.activeElement).to.eq($input.get(0)) - win.removeEventListener("blur", onBlur) + return cy + .window().blur().then(() => expect(blurred).to.be.true).get("input:first").focus().then($input => cy + .window().blur({ force: true }) + .then(function() { + expect(doc.activeElement).to.eq($input.get(0)); + return win.removeEventListener("blur", onBlur); + })); + }); - it "can blur [contenteditable]", -> - ce = cy.$$("[contenteditable]:first") + it("can blur [contenteditable]", function() { + const ce = cy.$$("[contenteditable]:first"); - cy - .get("[contenteditable]:first").focus().blur().then ($ce) -> - expect($ce.get(0)).to.eq ce.get(0) + return cy + .get("[contenteditable]:first").focus().blur().then($ce => expect($ce.get(0)).to.eq(ce.get(0))); + }); - it "can blur input[type=time]", -> - blurred = false + it("can blur input[type=time]", function() { + let blurred = false; - cy.$$("#time-without-value").blur -> - blurred = true + cy.$$("#time-without-value").blur(() => blurred = true); - cy + return cy .get("#time-without-value").focus().invoke("val", "03:15:00").blur() - .then -> - expect(blurred).to.be.true + .then(() => expect(blurred).to.be.true); + }); - it "can blur tabindex", -> - blurred = false + it("can blur tabindex", function() { + let blurred = false; cy - .$$("#comments").blur -> - blurred = true - .get(0).focus() + .$$("#comments").blur(() => blurred = true).get(0).focus(); - cy.get("#comments").blur().then -> - expect(blurred).to.be.true + return cy.get("#comments").blur().then(() => expect(blurred).to.be.true); + }); - it "can force blurring on a non-focused element", -> - blurred = false + it("can force blurring on a non-focused element", function() { + let blurred = false; - cy.$$("input:first").blur -> - blurred = true + cy.$$("input:first").blur(() => blurred = true); - cy + return cy .get("input:last").focus() .get("input:first").blur({force: true}) - .then -> - expect(blurred).to.be.true + .then(() => expect(blurred).to.be.true); + }); - it "can force blurring when there is no focused element", -> - blurred = false + it("can force blurring when there is no focused element", function() { + let blurred = false; - cy.$$("input:first").blur -> - blurred = true + cy.$$("input:first").blur(() => blurred = true); - cy + return cy .focused().should("not.exist") .get("input:first").blur({force: true}) - .then -> - expect(blurred).to.be.true - - it "can focus svg elements", -> - onBlur = cy.stub() - - cy.$$("[data-cy=rect]").blur(onBlur) - - cy.get("[data-cy=rect]").focus().blur().then -> - expect(onBlur).to.be.calledOnce + .then(() => expect(blurred).to.be.true); + }); - describe "assertion verification", -> - beforeEach -> - cy.on "log:added", (attrs, log) => - if log.get("name") is "assert" - @lastLog = log + it("can focus svg elements", function() { + const onBlur = cy.stub(); - return null + cy.$$("[data-cy=rect]").blur(onBlur); - it "eventually passes the assertion", -> - cy.$$(":text:first").blur -> - _.delay => - $(@).addClass("blured") - , 100 + return cy.get("[data-cy=rect]").focus().blur().then(() => expect(onBlur).to.be.calledOnce); + }); - cy.get(":text:first").focus().blur().should("have.class", "blured").then -> - lastLog = @lastLog - - expect(lastLog.get("name")).to.eq("assert") - expect(lastLog.get("state")).to.eq("passed") - expect(lastLog.get("ended")).to.be.true - - describe ".log", -> - beforeEach -> - @logs = [] - - cy.on "log:added", (attrs, log) => - if attrs.name is "blur" - @lastLog = log - @logs.push(log) - - return null - - it "logs immediately before resolving", -> - input = cy.$$(":text:first") - - expected = false - - cy.on "log:added", (attrs, log) -> - if log.get("name") is "blur" - expect(log.get("state")).to.eq("pending") - expect(log.get("$el").get(0)).to.eq input.get(0) - expected = true - - cy.get(":text:first").focus().blur().then -> - expect(expected).to.be.true - - it "snapshots after clicking", -> - cy.get(":text:first").focus().blur().then -> - lastLog = @lastLog - - expect(lastLog.get("snapshots").length).to.eq(1) - expect(lastLog.get("snapshots")[0]).to.be.an("object") - - it "passes in $el", -> - cy.get("input:first").focus().blur().then ($input) -> - lastLog = @lastLog - - expect(lastLog.get("$el")).to.eq $input - - it "logs 1 blur event", -> - cy - .get("input:first").focus().blur().then -> - expect(@logs.length).to.eq(1) - - it "logs delta options for {force: true}", -> - cy - .get("input:first").blur({force: true}).then -> - lastLog = @lastLog - - expect(lastLog.get("message")).to.eq("{force: true}") - - it "#consoleProps", -> - cy.get("input:first").focus().blur().then ($input) -> - expect(@lastLog.invoke("consoleProps")).to.deep.eq { - Command: "blur" - "Applied To": $input.get(0) + describe("assertion verification", function() { + beforeEach(function() { + cy.on("log:added", (attrs, log) => { + if (log.get("name") === "assert") { + return this.lastLog = log; } + }); - describe "errors", -> - beforeEach -> - Cypress.config("defaultCommandTimeout", 100) - - @logs = [] - - cy.on "log:added", (attrs, log) => - @lastLog = log - @logs.push(log) - - return null - - it "throws when not a dom subject", (done) -> - cy.on "fail", (err) -> - expect(err.message).to.include "`cy.blur()` failed because it requires a DOM element" - done() - - cy.noop({}).blur() + return null; + }); - it "throws when subject is not in the document", (done) -> - blurred = 0 - - $input = cy.$$("input:first").blur (e) -> - blurred += 1 - $input.focus -> - $input.remove() - return false - return false - - cy.on "fail", (err) -> - expect(blurred).to.eq 1 - expect(err.message).to.include "`cy.blur()` failed because this element" - expect(err.docsUrl).to.include "https://on.cypress.io/element-has-detached-from-dom" - done() - - cy.get("input:first").focus().blur().focus().blur() - - it "throws when subject is a collection of elements", (done) -> - num = cy.$$("textarea,:text").length - - cy.on "fail", (err) => - expect(err.message).to.include("`cy.blur()` can only be called on a single element. Your subject contained #{num} elements.") - expect(err.docsUrl).to.include("https://on.cypress.io/blur") - done() - - cy.get("textarea,:text").blur() - - it "throws when there isnt an activeElement", (done) -> - cy.on "fail", (err) -> - expect(err.message).to.include "`cy.blur()` can only be called when there is a currently focused element." - expect(err.docsUrl).to.include("https://on.cypress.io/blur") - done() - - cy.get("form:first").blur() - - it "throws when blur is called on a non-active element", (done) -> - cy.on "fail", (err) -> - expect(err.message).to.include "`cy.blur()` can only be called on the focused element. Currently the focused element is a: ``" - expect(err.docsUrl).to.include("https://on.cypress.io/blur") - done() - - cy.get("input:first").focus() - cy.get("#button").blur() - - it "logs delta options on error", (done) -> - cy.$$("button:first").click -> - $(@).remove() - - cy.on "fail", (err) => - lastLog = @lastLog - - expect(lastLog.get("message")).to.eq("{force: true}") - done() - - cy.get("button:first").click().blur({force: true}) - - it "logs once when not dom subject", (done) -> - cy.on "fail", (err) => - lastLog = @lastLog - - expect(@logs.length).to.eq(1) - expect(lastLog.get("error")).to.eq(err) - done() - - cy.blur() - - it "eventually fails the assertion", (done) -> - cy.on "fail", (err) => - lastLog = @lastLog - - expect(err.message).to.include(lastLog.get("error").message) - expect(err.message).not.to.include("undefined") - expect(lastLog.get("name")).to.eq("assert") - expect(lastLog.get("state")).to.eq("failed") - expect(lastLog.get("error")).to.be.an.instanceof(chai.AssertionError) - - done() + return it("eventually passes the assertion", function() { + cy.$$(":text:first").blur(function() { + return _.delay(() => { + return $(this).addClass("blured"); + } + , 100); + }); + + return cy.get(":text:first").focus().blur().should("have.class", "blured").then(function() { + const { + lastLog + } = this; + + expect(lastLog.get("name")).to.eq("assert"); + expect(lastLog.get("state")).to.eq("passed"); + return expect(lastLog.get("ended")).to.be.true; + }); + }); + }); + + describe(".log", function() { + beforeEach(function() { + this.logs = []; + + cy.on("log:added", (attrs, log) => { + if (attrs.name === "blur") { + this.lastLog = log; + return this.logs.push(log); + } + }); - cy.get(":text:first").focus().blur().should("have.class", "blured") + return null; + }); - it "does not log an additional log on failure", (done) -> - cy.on "fail", => - expect(@logs.length).to.eq(4) - done() + it("logs immediately before resolving", function() { + const input = cy.$$(":text:first"); - cy.get(":text:first").focus().blur().should("have.class", "blured") + let expected = false; - it "can handle window w/length > 1 as a subject", -> - cy.window().should('have.length', 2) - .focus() + cy.on("log:added", function(attrs, log) { + if (log.get("name") === "blur") { + expect(log.get("state")).to.eq("pending"); + expect(log.get("$el").get(0)).to.eq(input.get(0)); + return expected = true; + } + }); + + return cy.get(":text:first").focus().blur().then(() => expect(expected).to.be.true); + }); + + it("snapshots after clicking", () => cy.get(":text:first").focus().blur().then(function() { + const { + lastLog + } = this; + + expect(lastLog.get("snapshots").length).to.eq(1); + return expect(lastLog.get("snapshots")[0]).to.be.an("object"); + })); + + it("passes in $el", () => cy.get("input:first").focus().blur().then(function($input) { + const { + lastLog + } = this; + + return expect(lastLog.get("$el")).to.eq($input); + })); + + it("logs 1 blur event", () => cy + .get("input:first").focus().blur().then(function() { + return expect(this.logs.length).to.eq(1); + })); + + it("logs delta options for {force: true}", () => cy + .get("input:first").blur({force: true}).then(function() { + const { + lastLog + } = this; + + return expect(lastLog.get("message")).to.eq("{force: true}"); + })); + + return it("#consoleProps", () => cy.get("input:first").focus().blur().then(function($input) { + return expect(this.lastLog.invoke("consoleProps")).to.deep.eq({ + Command: "blur", + "Applied To": $input.get(0) + });})); + }); + + return describe("errors", function() { + beforeEach(function() { + Cypress.config("defaultCommandTimeout", 100); + + this.logs = []; + + cy.on("log:added", (attrs, log) => { + this.lastLog = log; + return this.logs.push(log); + }); + + return null; + }); + + it("throws when not a dom subject", function(done) { + cy.on("fail", function(err) { + expect(err.message).to.include("`cy.blur()` failed because it requires a DOM element"); + return done(); + }); + + return cy.noop({}).blur(); + }); + + it("throws when subject is not in the document", function(done) { + let blurred = 0; + + var $input = cy.$$("input:first").blur(function(e) { + blurred += 1; + $input.focus(function() { + $input.remove(); + return false; + }); + return false; + }); + + cy.on("fail", function(err) { + expect(blurred).to.eq(1); + expect(err.message).to.include("`cy.blur()` failed because this element"); + expect(err.docsUrl).to.include("https://on.cypress.io/element-has-detached-from-dom"); + return done(); + }); + + return cy.get("input:first").focus().blur().focus().blur(); + }); + + it("throws when subject is a collection of elements", function(done) { + const num = cy.$$("textarea,:text").length; + + cy.on("fail", err => { + expect(err.message).to.include(`\`cy.blur()\` can only be called on a single element. Your subject contained ${num} elements.`); + expect(err.docsUrl).to.include("https://on.cypress.io/blur"); + return done(); + }); + + return cy.get("textarea,:text").blur(); + }); + + it("throws when there isnt an activeElement", function(done) { + cy.on("fail", function(err) { + expect(err.message).to.include("`cy.blur()` can only be called when there is a currently focused element."); + expect(err.docsUrl).to.include("https://on.cypress.io/blur"); + return done(); + }); + + return cy.get("form:first").blur(); + }); + + it("throws when blur is called on a non-active element", function(done) { + cy.on("fail", function(err) { + expect(err.message).to.include("`cy.blur()` can only be called on the focused element. Currently the focused element is a: ``"); + expect(err.docsUrl).to.include("https://on.cypress.io/blur"); + return done(); + }); + + cy.get("input:first").focus(); + return cy.get("#button").blur(); + }); + + it("logs delta options on error", function(done) { + cy.$$("button:first").click(function() { + return $(this).remove(); + }); + + cy.on("fail", err => { + const { + lastLog + } = this; + + expect(lastLog.get("message")).to.eq("{force: true}"); + return done(); + }); + + return cy.get("button:first").click().blur({force: true}); + }); + + it("logs once when not dom subject", function(done) { + cy.on("fail", err => { + const { + lastLog + } = this; + + expect(this.logs.length).to.eq(1); + expect(lastLog.get("error")).to.eq(err); + return done(); + }); + + return cy.blur(); + }); + + it("eventually fails the assertion", function(done) { + cy.on("fail", err => { + const { + lastLog + } = this; + + expect(err.message).to.include(lastLog.get("error").message); + expect(err.message).not.to.include("undefined"); + expect(lastLog.get("name")).to.eq("assert"); + expect(lastLog.get("state")).to.eq("failed"); + expect(lastLog.get("error")).to.be.an.instanceof(chai.AssertionError); + + return done(); + }); + + return cy.get(":text:first").focus().blur().should("have.class", "blured"); + }); + + it("does not log an additional log on failure", function(done) { + cy.on("fail", () => { + expect(this.logs.length).to.eq(4); + return done(); + }); + + return cy.get(":text:first").focus().blur().should("have.class", "blured"); + }); + + return it("can handle window w/length > 1 as a subject", () => cy.window().should('have.length', 2) + .focus()); + }); + }); +}); diff --git a/packages/driver/test/cypress/integration/commands/actions/hover_spec.js b/packages/driver/test/cypress/integration/commands/actions/hover_spec.js index 8347c33c2282..9beef4de25d7 100644 --- a/packages/driver/test/cypress/integration/commands/actions/hover_spec.js +++ b/packages/driver/test/cypress/integration/commands/actions/hover_spec.js @@ -1,23 +1,33 @@ -$ = Cypress.$.bind(Cypress) -_ = Cypress._ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const $ = Cypress.$.bind(Cypress); +const { + _ +} = Cypress; -describe "src/cy/commands/actions/hover", -> - before -> - cy - .visit("/fixtures/dom.html") - .then (win) -> - @body = win.document.body.outerHTML +describe("src/cy/commands/actions/hover", function() { + before(() => cy + .visit("/fixtures/dom.html") + .then(function(win) { + return this.body = win.document.body.outerHTML; + })); - beforeEach -> - doc = cy.state("document") + beforeEach(function() { + const doc = cy.state("document"); - $(doc.body).empty().html(@body) + return $(doc.body).empty().html(this.body); + }); - context "#hover", -> - it "throws when invoking", (done) -> - cy.on "fail", (err) -> - expect(err.message).to.include "`cy.hover()` is not currently implemented." - expect(err.docsUrl).to.eq "https://on.cypress.io/hover" - done() + return context("#hover", () => it("throws when invoking", function(done) { + cy.on("fail", function(err) { + expect(err.message).to.include("`cy.hover()` is not currently implemented."); + expect(err.docsUrl).to.eq("https://on.cypress.io/hover"); + return done(); + }); - cy.get("button").hover() + return cy.get("button").hover(); + })); +}); diff --git a/packages/driver/test/cypress/integration/commands/actions/scroll_spec.js b/packages/driver/test/cypress/integration/commands/actions/scroll_spec.js index 8f845eba2078..4331c8caf2d1 100644 --- a/packages/driver/test/cypress/integration/commands/actions/scroll_spec.js +++ b/packages/driver/test/cypress/integration/commands/actions/scroll_spec.js @@ -1,750 +1,918 @@ -$ = Cypress.$Cypress.$ -_ = Cypress._ - -describe "src/cy/commands/actions/scroll", -> - before -> - cy - .visit("/fixtures/scrolling.html") - .then (win) -> - @body = win.document.body.outerHTML - - beforeEach -> - doc = cy.state("document") - - $(doc.body).empty().html(@body) - - cy.viewport(600, 200) - - context "#scrollTo", -> - beforeEach -> - @win = cy.state("window") - @scrollVert = cy.$$("#scroll-to-vertical") - @scrollHoriz = cy.$$("#scroll-to-horizontal") - @scrollBoth = cy.$$("#scroll-to-both") - - ## reset the scrollable containers back - ## to furthest left and top - @win.scrollTop = 0 - @win.scrollLeft = 0 - - @scrollVert.scrollTop = 0 - @scrollVert.scrollLeft = 0 - - @scrollHoriz.scrollTop = 0 - @scrollHoriz.scrollLeft = 0 - - @scrollBoth.scrollTop = 0 - @scrollBoth.scrollLeft = 0 - - describe "subject", -> - it "is window by default", -> - cy.scrollTo("125px").then (win2) -> - expect(@win).to.eq(win2) - - it "is DOM", -> - cy.get("#scroll-to-vertical").scrollTo("125px").then ($el) -> - expect($el.get(0)).to.eq @scrollVert.get(0) - - it "can use window", -> - cy.window().scrollTo("10px").then (win) -> - expect(win.scrollX).to.eq(10) - - it "can handle window w/length > 1 as a subject", -> - cy.visit('/fixtures/dom.html') - cy.window().should('have.length.gt', 1) - .scrollTo('10px') - - describe "x axis only", -> - it "scrolls x axis to num px", -> - expect(@scrollHoriz.get(0).scrollTop).to.eq(0) - expect(@scrollHoriz.get(0).scrollLeft).to.eq(0) - - cy.get("#scroll-to-horizontal").scrollTo(300).then ($el) -> - expect(@scrollHoriz.get(0).scrollTop).to.eq(0) - expect(@scrollHoriz.get(0).scrollLeft).to.eq(300) - - it "scrolls x axis to px", -> - expect(@scrollHoriz.get(0).scrollTop).to.eq(0) - expect(@scrollHoriz.get(0).scrollLeft).to.eq(0) - - cy.get("#scroll-to-horizontal").scrollTo("125px").then ($el) -> - expect(@scrollHoriz.get(0).scrollTop).to.eq(0) - expect(@scrollHoriz.get(0).scrollLeft).to.eq(125) - - it "scrolls x axis by % of scrollable height", -> - expect(@scrollHoriz.get(0).scrollTop).to.eq(0) - expect(@scrollHoriz.get(0).scrollLeft).to.eq(0) - - cy.get("#scroll-to-horizontal").scrollTo("50%").then ($el) -> - ## they don't calculate the height of the container - ## in the percentage of the scroll (since going the height - ## of the container wouldn't scroll at all...) - expect(@scrollHoriz.get(0).scrollTop).to.eq(0) - expect(@scrollHoriz.get(0).scrollLeft).to.eq((500-100)/2) - - describe "position arguments", -> - it "scrolls x/y axis to topLeft", -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) - - cy.get("#scroll-to-both").scrollTo("topLeft").then () -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) - - it "scrolls x/y axis to top", -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) - - cy.get("#scroll-to-both").scrollTo("top").then () -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq((500-100)/2) - - it "scrolls x/y axis to topRight", -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) - - cy.get("#scroll-to-both").scrollTo("topRight").then () -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq((500-100)) - - it "scrolls x/y axis to left", -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) - - cy.get("#scroll-to-both").scrollTo("left").then () -> - expect(@scrollBoth.get(0).scrollTop).to.eq((500-100)/2) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) - - it "scrolls x/y axis to center", -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) - - cy.get("#scroll-to-both").scrollTo("center").then () -> - expect(@scrollBoth.get(0).scrollTop).to.eq((500-100)/2) - expect(@scrollBoth.get(0).scrollLeft).to.eq((500-100)/2) - - it "scrolls x/y axis to right", -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const { + $ +} = Cypress.$Cypress; +const { + _ +} = Cypress; + +describe("src/cy/commands/actions/scroll", function() { + before(() => cy + .visit("/fixtures/scrolling.html") + .then(function(win) { + return this.body = win.document.body.outerHTML; + })); + + beforeEach(function() { + const doc = cy.state("document"); + + $(doc.body).empty().html(this.body); + + return cy.viewport(600, 200); + }); + + context("#scrollTo", function() { + beforeEach(function() { + this.win = cy.state("window"); + this.scrollVert = cy.$$("#scroll-to-vertical"); + this.scrollHoriz = cy.$$("#scroll-to-horizontal"); + this.scrollBoth = cy.$$("#scroll-to-both"); + + //# reset the scrollable containers back + //# to furthest left and top + this.win.scrollTop = 0; + this.win.scrollLeft = 0; + + this.scrollVert.scrollTop = 0; + this.scrollVert.scrollLeft = 0; + + this.scrollHoriz.scrollTop = 0; + this.scrollHoriz.scrollLeft = 0; + + this.scrollBoth.scrollTop = 0; + return this.scrollBoth.scrollLeft = 0; + }); + + describe("subject", function() { + it("is window by default", () => cy.scrollTo("125px").then(function(win2) { + return expect(this.win).to.eq(win2); + })); + + it("is DOM", () => cy.get("#scroll-to-vertical").scrollTo("125px").then(function($el) { + return expect($el.get(0)).to.eq(this.scrollVert.get(0)); + })); + + it("can use window", () => cy.window().scrollTo("10px").then(win => expect(win.scrollX).to.eq(10))); + + return it("can handle window w/length > 1 as a subject", function() { + cy.visit('/fixtures/dom.html'); + return cy.window().should('have.length.gt', 1) + .scrollTo('10px'); + }); + }); + + describe("x axis only", function() { + it("scrolls x axis to num px", function() { + expect(this.scrollHoriz.get(0).scrollTop).to.eq(0); + expect(this.scrollHoriz.get(0).scrollLeft).to.eq(0); + + return cy.get("#scroll-to-horizontal").scrollTo(300).then(function($el) { + expect(this.scrollHoriz.get(0).scrollTop).to.eq(0); + return expect(this.scrollHoriz.get(0).scrollLeft).to.eq(300); + }); + }); + + it("scrolls x axis to px", function() { + expect(this.scrollHoriz.get(0).scrollTop).to.eq(0); + expect(this.scrollHoriz.get(0).scrollLeft).to.eq(0); + + return cy.get("#scroll-to-horizontal").scrollTo("125px").then(function($el) { + expect(this.scrollHoriz.get(0).scrollTop).to.eq(0); + return expect(this.scrollHoriz.get(0).scrollLeft).to.eq(125); + }); + }); + + return it("scrolls x axis by % of scrollable height", function() { + expect(this.scrollHoriz.get(0).scrollTop).to.eq(0); + expect(this.scrollHoriz.get(0).scrollLeft).to.eq(0); + + return cy.get("#scroll-to-horizontal").scrollTo("50%").then(function($el) { + //# they don't calculate the height of the container + //# in the percentage of the scroll (since going the height + //# of the container wouldn't scroll at all...) + expect(this.scrollHoriz.get(0).scrollTop).to.eq(0); + return expect(this.scrollHoriz.get(0).scrollLeft).to.eq((500-100)/2); + }); + }); + }); + + describe("position arguments", function() { + it("scrolls x/y axis to topLeft", function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); + + return cy.get("#scroll-to-both").scrollTo("topLeft").then(function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + return expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); + }); + }); + + it("scrolls x/y axis to top", function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); + + return cy.get("#scroll-to-both").scrollTo("top").then(function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + return expect(this.scrollBoth.get(0).scrollLeft).to.eq((500-100)/2); + }); + }); + + it("scrolls x/y axis to topRight", function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); + + return cy.get("#scroll-to-both").scrollTo("topRight").then(function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + return expect(this.scrollBoth.get(0).scrollLeft).to.eq((500-100)); + }); + }); + + it("scrolls x/y axis to left", function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); + + return cy.get("#scroll-to-both").scrollTo("left").then(function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq((500-100)/2); + return expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); + }); + }); + + it("scrolls x/y axis to center", function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); + + return cy.get("#scroll-to-both").scrollTo("center").then(function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq((500-100)/2); + return expect(this.scrollBoth.get(0).scrollLeft).to.eq((500-100)/2); + }); + }); + + it("scrolls x/y axis to right", function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); + + return cy.get("#scroll-to-both").scrollTo("right").then(function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq((500-100)/2); + return expect(this.scrollBoth.get(0).scrollLeft).to.eq((500-100)); + }); + }); + + it("scrolls x/y axis to bottomLeft", function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); + + return cy.get("#scroll-to-both").scrollTo("bottomLeft").then(function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq((500-100)); + return expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); + }); + }); + + it("scrolls x/y axis to bottom", function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); + + return cy.get("#scroll-to-both").scrollTo("bottom").then(function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq((500-100)); + return expect(this.scrollBoth.get(0).scrollLeft).to.eq((500-100)/2); + }); + }); + + return it("scrolls x/y axis to bottomRight", function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); + + return cy.get("#scroll-to-both").scrollTo("bottomRight").then(function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq((500-100)); + return expect(this.scrollBoth.get(0).scrollLeft).to.eq((500-100)); + }); + }); + }); + + describe("scroll both axis", function() { + it("scrolls both x and y axis num of px", function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); + + return cy.get("#scroll-to-both").scrollTo(300, 150).then(function($el) { + expect(this.scrollBoth.get(0).scrollTop).to.eq(150); + return expect(this.scrollBoth.get(0).scrollLeft).to.eq(300); + }); + }); + + it("scrolls x to 0 and y num of px", function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); + + return cy.get("#scroll-to-both").scrollTo(0, 150).then(function($el) { + expect(this.scrollBoth.get(0).scrollTop).to.eq(150); + return expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); + }); + }); + + it("scrolls x num of px and y to 0 ", function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); + + return cy.get("#scroll-to-both").scrollTo(150, 0).then(function($el) { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + return expect(this.scrollBoth.get(0).scrollLeft).to.eq(150); + }); + }); + + it("scrolls both x and y axis of px", function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); + + return cy.get("#scroll-to-both").scrollTo("300px", "150px").then(function($el) { + expect(this.scrollBoth.get(0).scrollTop).to.eq(150); + return expect(this.scrollBoth.get(0).scrollLeft).to.eq(300); + }); + }); + + it("scrolls both x and y axis of percentage", function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); + + return cy.get("#scroll-to-both").scrollTo("50%", "50%").then(function($el) { + expect(this.scrollBoth.get(0).scrollTop).to.eq((500-100)/2); + return expect(this.scrollBoth.get(0).scrollLeft).to.eq((500-100)/2); + }); + }); + + it("scrolls x to 0 and y percentage", function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); + + return cy.get("#scroll-to-both").scrollTo("0%", "50%").then(function($el) { + expect(this.scrollBoth.get(0).scrollTop).to.eq((500-100)/2); + return expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); + }); + }); + + return it("scrolls x to percentage and y to 0", function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); + + return cy.get("#scroll-to-both").scrollTo("50%", "0%").then(function($el) { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + return expect(this.scrollBoth.get(0).scrollLeft).to.eq((500-100)/2); + }); + }); + }); + + describe("scrolls with options", function() { + it("calls jQuery scroll to", function() { + const scrollTo = cy.spy($.fn, "scrollTo"); + + return cy.get("#scroll-to-both").scrollTo("25px").then(() => expect(scrollTo).to.be.calledWith({left: "25px", top: 0})); + }); + + it("sets duration to 0 by default", function() { + const scrollTo = cy.spy($.fn, "scrollTo"); + + return cy.get("#scroll-to-both").scrollTo("25px").then(() => expect(scrollTo).to.be.calledWithMatch({}, {duration: 0})); + }); + + it("sets axis to correct xy", function() { + const scrollTo = cy.spy($.fn, "scrollTo"); + + return cy.get("#scroll-to-both").scrollTo("25px", "80px").then(() => expect(scrollTo).to.be.calledWithMatch({}, {axis: "xy"})); + }); + + it("scrolling resolves after a set duration", function() { + expect(this.scrollHoriz.get(0).scrollTop).to.eq(0); + expect(this.scrollHoriz.get(0).scrollLeft).to.eq(0); + + const scrollTo = cy.spy($.fn, "scrollTo"); + + return cy.get("#scroll-to-horizontal").scrollTo("125px", {duration: 500}).then(function() { + expect(scrollTo).to.be.calledWithMatch({}, {duration: 500}); + expect(this.scrollHoriz.get(0).scrollTop).to.eq(0); + return expect(this.scrollHoriz.get(0).scrollLeft).to.eq(125); + }); + }); + + it("accepts duration string option", function() { + const scrollTo = cy.spy($.fn, "scrollTo"); + + return cy.get("#scroll-to-both").scrollTo("25px", {duration: "500"}).then(() => expect(scrollTo.args[0][1].duration).to.eq("500")); + }); + + it("has easing set to swing by default", function() { + const scrollTo = cy.spy($.fn, "scrollTo"); + + return cy.get("#scroll-to-both").scrollTo("25px").then(() => expect(scrollTo.args[0][1].easing).to.eq("swing")); + }); + + it("scrolling resolves after easing", function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); + + const scrollTo = cy.spy($.fn, "scrollTo"); + + return cy.get("#scroll-to-both").scrollTo("25px", "50px", {easing: "linear"}).then(function() { + expect(scrollTo).to.be.calledWithMatch({}, {easing: "linear"}); + expect(this.scrollBoth.get(0).scrollTop).to.eq(50); + return expect(this.scrollBoth.get(0).scrollLeft).to.eq(25); + }); + }); + + return it("retries until element is scrollable", function() { + const $container = cy.$$("#nonscroll-becomes-scrollable"); + + expect($container.get(0).scrollTop).to.eq(0); + expect($container.get(0).scrollLeft).to.eq(0); + + let retried = false; + + cy.on("command:retry", _.after(2, function() { + $container.css("overflow", "scroll"); + return retried = true; + }) + ); + + return cy.get("#nonscroll-becomes-scrollable").scrollTo(500, 300).then(function() { + expect(retried).to.be.true; + expect($container.get(0).scrollTop).to.eq(300); + return expect($container.get(0).scrollLeft).to.eq(500); + }); + }); + }); - cy.get("#scroll-to-both").scrollTo("right").then () -> - expect(@scrollBoth.get(0).scrollTop).to.eq((500-100)/2) - expect(@scrollBoth.get(0).scrollLeft).to.eq((500-100)) + describe("assertion verification", function() { + beforeEach(function() { + cy.on("log:added", (attrs, log) => { + if (log.get("name") === "assert") { + return this.lastLog = log; + } + }); - it "scrolls x/y axis to bottomLeft", -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) + return null; + }); - cy.get("#scroll-to-both").scrollTo("bottomLeft").then () -> - expect(@scrollBoth.get(0).scrollTop).to.eq((500-100)) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) + it("eventually passes the assertion", function() { + cy.on("command:retry", _.after(2, () => cy.$$("#scroll-into-view-horizontal").addClass("scrolled")) + ); - it "scrolls x/y axis to bottom", -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) - - cy.get("#scroll-to-both").scrollTo("bottom").then () -> - expect(@scrollBoth.get(0).scrollTop).to.eq((500-100)) - expect(@scrollBoth.get(0).scrollLeft).to.eq((500-100)/2) - - it "scrolls x/y axis to bottomRight", -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) - - cy.get("#scroll-to-both").scrollTo("bottomRight").then () -> - expect(@scrollBoth.get(0).scrollTop).to.eq((500-100)) - expect(@scrollBoth.get(0).scrollLeft).to.eq((500-100)) - - describe "scroll both axis", -> - it "scrolls both x and y axis num of px", -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) - - cy.get("#scroll-to-both").scrollTo(300, 150).then ($el) -> - expect(@scrollBoth.get(0).scrollTop).to.eq(150) - expect(@scrollBoth.get(0).scrollLeft).to.eq(300) - - it "scrolls x to 0 and y num of px", -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) - - cy.get("#scroll-to-both").scrollTo(0, 150).then ($el) -> - expect(@scrollBoth.get(0).scrollTop).to.eq(150) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) - - it "scrolls x num of px and y to 0 ", -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) - - cy.get("#scroll-to-both").scrollTo(150, 0).then ($el) -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq(150) - - it "scrolls both x and y axis of px", -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) - - cy.get("#scroll-to-both").scrollTo("300px", "150px").then ($el) -> - expect(@scrollBoth.get(0).scrollTop).to.eq(150) - expect(@scrollBoth.get(0).scrollLeft).to.eq(300) - - it "scrolls both x and y axis of percentage", -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) - - cy.get("#scroll-to-both").scrollTo("50%", "50%").then ($el) -> - expect(@scrollBoth.get(0).scrollTop).to.eq((500-100)/2) - expect(@scrollBoth.get(0).scrollLeft).to.eq((500-100)/2) - - it "scrolls x to 0 and y percentage", -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) - - cy.get("#scroll-to-both").scrollTo("0%", "50%").then ($el) -> - expect(@scrollBoth.get(0).scrollTop).to.eq((500-100)/2) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) - - it "scrolls x to percentage and y to 0", -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) - - cy.get("#scroll-to-both").scrollTo("50%", "0%").then ($el) -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq((500-100)/2) - - describe "scrolls with options", -> - it "calls jQuery scroll to", -> - scrollTo = cy.spy($.fn, "scrollTo") - - cy.get("#scroll-to-both").scrollTo("25px").then -> - expect(scrollTo).to.be.calledWith({left: "25px", top: 0}) - - it "sets duration to 0 by default", -> - scrollTo = cy.spy($.fn, "scrollTo") - - cy.get("#scroll-to-both").scrollTo("25px").then -> - expect(scrollTo).to.be.calledWithMatch({}, {duration: 0}) - - it "sets axis to correct xy", -> - scrollTo = cy.spy($.fn, "scrollTo") - - cy.get("#scroll-to-both").scrollTo("25px", "80px").then -> - expect(scrollTo).to.be.calledWithMatch({}, {axis: "xy"}) - - it "scrolling resolves after a set duration", -> - expect(@scrollHoriz.get(0).scrollTop).to.eq(0) - expect(@scrollHoriz.get(0).scrollLeft).to.eq(0) - - scrollTo = cy.spy($.fn, "scrollTo") - - cy.get("#scroll-to-horizontal").scrollTo("125px", {duration: 500}).then -> - expect(scrollTo).to.be.calledWithMatch({}, {duration: 500}) - expect(@scrollHoriz.get(0).scrollTop).to.eq(0) - expect(@scrollHoriz.get(0).scrollLeft).to.eq(125) - - it "accepts duration string option", -> - scrollTo = cy.spy($.fn, "scrollTo") - - cy.get("#scroll-to-both").scrollTo("25px", {duration: "500"}).then -> - expect(scrollTo.args[0][1].duration).to.eq "500" - - it "has easing set to swing by default", -> - scrollTo = cy.spy($.fn, "scrollTo") - - cy.get("#scroll-to-both").scrollTo("25px").then -> - expect(scrollTo.args[0][1].easing).to.eq "swing" - - it "scrolling resolves after easing", -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) - - scrollTo = cy.spy($.fn, "scrollTo") - - cy.get("#scroll-to-both").scrollTo("25px", "50px", {easing: "linear"}).then -> - expect(scrollTo).to.be.calledWithMatch({}, {easing: "linear"}) - expect(@scrollBoth.get(0).scrollTop).to.eq(50) - expect(@scrollBoth.get(0).scrollLeft).to.eq(25) - - it "retries until element is scrollable", -> - $container = cy.$$("#nonscroll-becomes-scrollable") - - expect($container.get(0).scrollTop).to.eq(0) - expect($container.get(0).scrollLeft).to.eq(0) - - retried = false - - cy.on "command:retry", _.after 2, -> - $container.css("overflow", "scroll") - retried = true - - cy.get("#nonscroll-becomes-scrollable").scrollTo(500, 300).then -> - expect(retried).to.be.true - expect($container.get(0).scrollTop).to.eq(300) - expect($container.get(0).scrollLeft).to.eq(500) - - describe "assertion verification", -> - beforeEach -> - cy.on "log:added", (attrs, log) => - if log.get("name") is "assert" - @lastLog = log - - return null - - it "eventually passes the assertion", -> - cy.on "command:retry", _.after 2, -> - cy.$$("#scroll-into-view-horizontal").addClass("scrolled") - - cy + return cy .get("#scroll-into-view-horizontal") .scrollTo("right") - .should("have.class", "scrolled").then -> - lastLog = @lastLog - - expect(lastLog.get("name")).to.eq("assert") - expect(lastLog.get("state")).to.eq("passed") - expect(lastLog.get("ended")).to.be.true - - it "waits until the subject is scrollable", -> + .should("have.class", "scrolled").then(function() { + const { + lastLog + } = this; + + expect(lastLog.get("name")).to.eq("assert"); + expect(lastLog.get("state")).to.eq("passed"); + return expect(lastLog.get("ended")).to.be.true; + }); + }); + + return it("waits until the subject is scrollable", function() { cy.stub(cy, "ensureScrollability") - .onFirstCall().throws(new Error()) + .onFirstCall().throws(new Error()); - cy.on "command:retry", -> - cy.ensureScrollability.returns() + cy.on("command:retry", () => cy.ensureScrollability.returns()); - cy + return cy .get("#scroll-into-view-horizontal") - .scrollTo("right").then -> - expect(cy.ensureScrollability).to.be.calledTwice - - describe "errors", -> - beforeEach -> - Cypress.config("defaultCommandTimeout", 50) - - @logs = [] - - cy.on "log:added", (attrs, log) => - @lastLog = log - @logs.push(log) - - return null - - it "throws when subject isn't scrollable", (done) -> - cy.on "fail", (err) => - expect(err.message).to.include "`cy.scrollTo()` failed because this element is not scrollable:" - done() - - cy.get("button:first").scrollTo("bottom") - - context "subject errors", -> - it "throws when not passed DOM element as subject", (done) -> - cy.on "fail", (err) => - expect(err.message).to.include "`cy.scrollTo()` failed because it requires a DOM element." - expect(err.message).to.include "{foo: bar}" - expect(err.message).to.include "> `cy.noop()`" - done() - - cy.noop({foo: "bar"}).scrollTo("250px") - - it "throws if scrollable container is multiple elements", (done) -> - cy.on "fail", (err) => - expect(err.message).to.include "`cy.scrollTo()` can only be used to scroll 1 element, you tried to scroll 2 elements." - expect(err.docsUrl).to.eq("https://on.cypress.io/scrollto") - done() - - cy.get("button").scrollTo("500px") - - context "argument errors", -> - it "throws if no args passed", (done) -> - cy.on "fail", (err) => - expect(err.message).to.include "`cy.scrollTo()` must be called with a valid `position`. It can be a string, number or object." - expect(err.docsUrl).to.eq("https://on.cypress.io/scrollto") - done() - - cy.scrollTo() - - it "throws if NaN", (done) -> - cy.on "fail", (err) => - expect(err.message).to.include "`cy.scrollTo()` must be called with a valid `position`. It can be a string, number or object. Your position was: `25, NaN`" - expect(err.docsUrl).to.eq("https://on.cypress.io/scrollto") - done() - - cy.get("#scroll-to-both").scrollTo(25, 0/0) - - it "throws if Infinity", (done) -> - cy.on "fail", (err) => - expect(err.message).to.include "`cy.scrollTo()` must be called with a valid `position`. It can be a string, number or object. Your position was: `25, Infinity`" - expect(err.docsUrl).to.eq("https://on.cypress.io/scrollto") - done() - - cy.get("#scroll-to-both").scrollTo(25, 10/0) - - it "throws if unrecognized position", (done) -> - cy.on "fail", (err) => - expect(err.message).to.include "Invalid position argument: `botom`. Position may only be topLeft, top, topRight, left, center, right, bottomLeft, bottom, bottomRight." - done() - - cy.get("#scroll-to-both").scrollTo("botom") - - context "option errors", -> - it "throws if duration is not a number or valid string", (done) -> - cy.on "fail", (err) => - expect(err.message).to.include "`cy.scrollTo()` must be called with a valid `duration`. Duration may be either a number (ms) or a string representing a number (ms). Your duration was: `foo`" - expect(err.docsUrl).to.eq("https://on.cypress.io/scrollto") - done() - - cy.get("#scroll-to-both").scrollTo("25px", { duration: "foo" }) - - it "throws if unrecognized easing", (done) -> - cy.on "fail", (err) => - expect(err.message).to.include "`cy.scrollTo()` must be called with a valid `easing`. Your easing was: `flower`" - expect(err.docsUrl).to.eq("https://on.cypress.io/scrollto") - done() - - cy.get("#scroll-to-both").scrollTo("25px", { easing: "flower" }) - - describe ".log", -> - beforeEach -> - @logs = [] - - cy.on "log:added", (attrs, log) => - @lastLog = log - @logs.push(log) - - return null - - it "logs out scrollTo", -> - cy.get("#scroll-to-both").scrollTo(25).then -> - lastLog = @lastLog - - expect(lastLog.get("name")).to.eq "scrollTo" - - it "passes in $el if child command", -> - cy.get("#scroll-to-both").scrollTo(25).then ($container) -> - lastLog = @lastLog - - expect(lastLog.get("$el").get(0)).to.eq $container.get(0) + .scrollTo("right").then(() => expect(cy.ensureScrollability).to.be.calledTwice); + }); + }); + + describe("errors", function() { + beforeEach(function() { + Cypress.config("defaultCommandTimeout", 50); + + this.logs = []; + + cy.on("log:added", (attrs, log) => { + this.lastLog = log; + return this.logs.push(log); + }); + + return null; + }); + + it("throws when subject isn't scrollable", function(done) { + cy.on("fail", err => { + expect(err.message).to.include("`cy.scrollTo()` failed because this element is not scrollable:"); + return done(); + }); + + return cy.get("button:first").scrollTo("bottom"); + }); + + context("subject errors", function() { + it("throws when not passed DOM element as subject", function(done) { + cy.on("fail", err => { + expect(err.message).to.include("`cy.scrollTo()` failed because it requires a DOM element."); + expect(err.message).to.include("{foo: bar}"); + expect(err.message).to.include("> `cy.noop()`"); + return done(); + }); + + return cy.noop({foo: "bar"}).scrollTo("250px"); + }); + + return it("throws if scrollable container is multiple elements", function(done) { + cy.on("fail", err => { + expect(err.message).to.include("`cy.scrollTo()` can only be used to scroll 1 element, you tried to scroll 2 elements."); + expect(err.docsUrl).to.eq("https://on.cypress.io/scrollto"); + return done(); + }); + + return cy.get("button").scrollTo("500px"); + }); + }); + + context("argument errors", function() { + it("throws if no args passed", function(done) { + cy.on("fail", err => { + expect(err.message).to.include("`cy.scrollTo()` must be called with a valid `position`. It can be a string, number or object."); + expect(err.docsUrl).to.eq("https://on.cypress.io/scrollto"); + return done(); + }); + + return cy.scrollTo(); + }); + + it("throws if NaN", function(done) { + cy.on("fail", err => { + expect(err.message).to.include("`cy.scrollTo()` must be called with a valid `position`. It can be a string, number or object. Your position was: `25, NaN`"); + expect(err.docsUrl).to.eq("https://on.cypress.io/scrollto"); + return done(); + }); + + return cy.get("#scroll-to-both").scrollTo(25, 0/0); + }); + + it("throws if Infinity", function(done) { + cy.on("fail", err => { + expect(err.message).to.include("`cy.scrollTo()` must be called with a valid `position`. It can be a string, number or object. Your position was: `25, Infinity`"); + expect(err.docsUrl).to.eq("https://on.cypress.io/scrollto"); + return done(); + }); + + return cy.get("#scroll-to-both").scrollTo(25, 10/0); + }); + + return it("throws if unrecognized position", function(done) { + cy.on("fail", err => { + expect(err.message).to.include("Invalid position argument: `botom`. Position may only be topLeft, top, topRight, left, center, right, bottomLeft, bottom, bottomRight."); + return done(); + }); + + return cy.get("#scroll-to-both").scrollTo("botom"); + }); + }); + + return context("option errors", function() { + it("throws if duration is not a number or valid string", function(done) { + cy.on("fail", err => { + expect(err.message).to.include("`cy.scrollTo()` must be called with a valid `duration`. Duration may be either a number (ms) or a string representing a number (ms). Your duration was: `foo`"); + expect(err.docsUrl).to.eq("https://on.cypress.io/scrollto"); + return done(); + }); + + return cy.get("#scroll-to-both").scrollTo("25px", { duration: "foo" }); + }); + + return it("throws if unrecognized easing", function(done) { + cy.on("fail", err => { + expect(err.message).to.include("`cy.scrollTo()` must be called with a valid `easing`. Your easing was: `flower`"); + expect(err.docsUrl).to.eq("https://on.cypress.io/scrollto"); + return done(); + }); + + return cy.get("#scroll-to-both").scrollTo("25px", { easing: "flower" }); + }); + }); + }); + + return describe(".log", function() { + beforeEach(function() { + this.logs = []; + + cy.on("log:added", (attrs, log) => { + this.lastLog = log; + return this.logs.push(log); + }); + + return null; + }); + + it("logs out scrollTo", () => cy.get("#scroll-to-both").scrollTo(25).then(function() { + const { + lastLog + } = this; + + return expect(lastLog.get("name")).to.eq("scrollTo"); + })); + + it("passes in $el if child command", () => cy.get("#scroll-to-both").scrollTo(25).then(function($container) { + const { + lastLog + } = this; + + return expect(lastLog.get("$el").get(0)).to.eq($container.get(0)); + })); + + it("passes undefined in $el if parent command", () => cy.scrollTo(25).then(function($container) { + const { + lastLog + } = this; + + return expect(lastLog.get("$el")).to.be.undefined; + })); + + it("logs duration options", () => cy.get("#scroll-to-both").scrollTo(25, { duration: 1 }).then(function() { + const { + lastLog + } = this; + + return expect(lastLog.get("message")).to.eq("25, 0, {duration: 1}"); + })); + + it("logs easing options", () => cy.get("#scroll-to-both").scrollTo(25, { easing: 'linear' }).then(function() { + const { + lastLog + } = this; + + return expect(lastLog.get("message")).to.eq("25, 0, {easing: linear}"); + })); + + it("snapshots immediately", () => cy.get("#scroll-to-both").scrollTo(25, { duration: 1 }).then(function() { + const { + lastLog + } = this; + + expect(lastLog.get("snapshots").length).to.eq(1); + return expect(lastLog.get("snapshots")[0]).to.be.an("object"); + })); + + return it("#consoleProps", () => cy.get("#scroll-to-both").scrollTo(25, {duration: 1}).then(function($container) { + const console = this.lastLog.invoke("consoleProps"); + expect(console.Command).to.eq("scrollTo"); + expect(console.X).to.eq(25); + expect(console.Y).to.eq(0); + expect(console.Options).to.eq("{duration: 1}"); + return expect(console["Scrolled Element"]).to.eq($container.get(0)); + })); + }); + }); + + return context("#scrollIntoView", function() { + beforeEach(function() { + this.win = cy.state("window"); + this.scrollVert = cy.$$("#scroll-into-view-vertical"); + this.scrollHoriz = cy.$$("#scroll-into-view-horizontal"); + this.scrollBoth = cy.$$("#scroll-into-view-both"); + + //# reset the scrollable containers back + //# to furthest left and top + this.win.scrollTo(0, 0); + + this.scrollVert.scrollTop(0); + this.scrollVert.scrollLeft(0); + + this.scrollHoriz.scrollTop(0); + this.scrollHoriz.scrollLeft(0); + + this.scrollBoth.scrollTop(0); + return this.scrollBoth.scrollLeft(0); + }); + + it("does not change the subject", function() { + const div = cy.$$("#scroll-into-view-vertical div"); + + return cy.get("#scroll-into-view-vertical div").scrollIntoView().then($div => expect($div).to.match(div)); + }); + + it("scrolls x axis of window to element", function() { + expect(this.win.scrollY).to.eq(0); + expect(this.win.scrollX).to.eq(0); + + cy.get("#scroll-into-view-win-horizontal div").scrollIntoView(); + return cy.window().then(function(win) { + expect(win.scrollY).to.eq(0); + return expect(win.scrollX).not.to.eq(0); + }); + }); + + it("scrolls y axis of window to element", function() { + expect(this.win.scrollY).to.eq(0); + expect(this.win.scrollX).to.eq(0); + + cy.get("#scroll-into-view-win-vertical div").scrollIntoView(); + return cy.window().then(function(win) { + expect(win.pageYOffset).not.to.eq(0); + return expect(Math.floor(win.pageXOffset)).closeTo(200, 2); + }); + }); + + it("scrolls both axes of window to element", function() { + expect(this.win.scrollY).to.eq(0); + expect(this.win.scrollX).to.eq(0); + + cy.get("#scroll-into-view-win-both div").scrollIntoView(); + return cy.window().then(function(win) { + expect(win.scrollY).not.to.eq(0); + return expect(win.scrollX).not.to.eq(0); + }); + }); + + it("scrolls x axis of container to element", function() { + expect(this.scrollHoriz.get(0).scrollTop).to.eq(0); + expect(this.scrollHoriz.get(0).scrollLeft).to.eq(0); + + return cy.get("#scroll-into-view-horizontal h5").scrollIntoView().then(function($el) { + expect(this.scrollHoriz.get(0).scrollTop).to.eq(0); + return expect(this.scrollHoriz.get(0).scrollLeft).to.eq(300); + }); + }); + + it("scrolls y axis of container to element", function() { + expect(this.scrollVert.get(0).scrollTop).to.eq(0); + expect(this.scrollVert.get(0).scrollLeft).to.eq(0); + + return cy.get("#scroll-into-view-vertical h5").scrollIntoView().then(function($el) { + expect(this.scrollVert.get(0).scrollTop).to.eq(300); + return expect(this.scrollVert.get(0).scrollLeft).to.eq(0); + }); + }); + + it("scrolls both axes of container to element", function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); + + return cy.get("#scroll-into-view-both h5").scrollIntoView().then(function($el) { + expect(this.scrollBoth.get(0).scrollTop).to.eq(300); + return expect(this.scrollBoth.get(0).scrollLeft).to.eq(300); + }); + }); + + it("calls jQuery scroll to", function() { + const scrollTo = cy.spy($.fn, "scrollTo"); + + return cy.get("#scroll-into-view-both h5").scrollIntoView().then(() => expect(scrollTo).to.be.called); + }); + + it("sets duration to 0 by default", function() { + const scrollTo = cy.spy($.fn, "scrollTo"); + + return cy.get("#scroll-into-view-both h5").scrollIntoView().then(() => expect(scrollTo).to.be.calledWithMatch({}, {duration: 0})); + }); + + it("sets axis to correct x or y", function() { + const scrollTo = cy.spy($.fn, "scrollTo"); - it "passes undefined in $el if parent command", -> - cy.scrollTo(25).then ($container) -> - lastLog = @lastLog + return cy.get("#scroll-into-view-both h5").scrollIntoView().then(() => expect(scrollTo).to.be.calledWithMatch({}, {axis: "xy"})); + }); - expect(lastLog.get("$el")).to.be.undefined + it("scrolling resolves after a set duration", function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); - it "logs duration options", -> - cy.get("#scroll-to-both").scrollTo(25, { duration: 1 }).then -> - lastLog = @lastLog + const scrollTo = cy.spy($.fn, "scrollTo"); - expect(lastLog.get("message")).to.eq "25, 0, {duration: 1}" + return cy.get("#scroll-into-view-both h5").scrollIntoView({duration: 500}).then(function() { + expect(scrollTo).to.be.calledWithMatch({}, {duration: 500}); + expect(this.scrollBoth.get(0).scrollLeft).to.eq(300); + return expect(this.scrollBoth.get(0).scrollTop).to.eq(300); + }); + }); - it "logs easing options", -> - cy.get("#scroll-to-both").scrollTo(25, { easing: 'linear' }).then -> - lastLog = @lastLog + it("accepts duration string option", function() { + const scrollTo = cy.spy($.fn, "scrollTo"); - expect(lastLog.get("message")).to.eq "25, 0, {easing: linear}" + return cy.get("#scroll-into-view-both h5").scrollIntoView({duration: "500"}).then(() => expect(scrollTo.args[0][1].duration).to.eq("500")); + }); + + it("accepts offset string option", function() { + const scrollTo = cy.spy($.fn, "scrollTo"); + + return cy.get("#scroll-into-view-both h5").scrollIntoView({offset: 500}).then(() => expect(scrollTo.args[0][1].offset).to.eq(500)); + }); + + it("accepts offset object option", function() { + const scrollTo = cy.spy($.fn, "scrollTo"); - it "snapshots immediately", -> - cy.get("#scroll-to-both").scrollTo(25, { duration: 1 }).then -> - lastLog = @lastLog + return cy.get("#scroll-into-view-both h5").scrollIntoView({offset: {left: 500, top: 200}}).then(() => expect(scrollTo.args[0][1].offset).to.deep.eq({left: 500, top: 200})); + }); + + it("has easing set to swing by default", function() { + const scrollTo = cy.spy($.fn, "scrollTo"); - expect(lastLog.get("snapshots").length).to.eq(1) - expect(lastLog.get("snapshots")[0]).to.be.an("object") + return cy.get("#scroll-into-view-both h5").scrollIntoView().then(() => expect(scrollTo.args[0][1].easing).to.eq("swing")); + }); - it "#consoleProps", -> - cy.get("#scroll-to-both").scrollTo(25, {duration: 1}).then ($container) -> - console = @lastLog.invoke("consoleProps") - expect(console.Command).to.eq("scrollTo") - expect(console.X).to.eq(25) - expect(console.Y).to.eq(0) - expect(console.Options).to.eq("{duration: 1}") - expect(console["Scrolled Element"]).to.eq $container.get(0) + it("scrolling resolves after easing", function() { + expect(this.scrollBoth.get(0).scrollTop).to.eq(0); + expect(this.scrollBoth.get(0).scrollLeft).to.eq(0); - context "#scrollIntoView", -> - beforeEach -> - @win = cy.state("window") - @scrollVert = cy.$$("#scroll-into-view-vertical") - @scrollHoriz = cy.$$("#scroll-into-view-horizontal") - @scrollBoth = cy.$$("#scroll-into-view-both") + const scrollTo = cy.spy($.fn, "scrollTo"); - ## reset the scrollable containers back - ## to furthest left and top - @win.scrollTo(0, 0) + return cy.get("#scroll-into-view-both h5").scrollIntoView({easing: "linear"}).then(function() { + expect(scrollTo).to.be.calledWithMatch({}, {easing: "linear"}); + expect(this.scrollBoth.get(0).scrollTop).to.eq(300); + return expect(this.scrollBoth.get(0).scrollLeft).to.eq(300); + }); + }); - @scrollVert.scrollTop(0) - @scrollVert.scrollLeft(0) + describe("assertion verification", function() { + beforeEach(function() { + cy.on("log:added", (attrs, log) => { + if (log.get("name") === "assert") { + return this.lastLog = log; + } + }); - @scrollHoriz.scrollTop(0) - @scrollHoriz.scrollLeft(0) + return null; + }); - @scrollBoth.scrollTop(0) - @scrollBoth.scrollLeft(0) + return it("eventually passes the assertion", function() { + cy.on("command:retry", _.after(2, () => cy.$$("#scroll-into-view-win-vertical div").addClass("scrolled")) + ); - it "does not change the subject", -> - div = cy.$$("#scroll-into-view-vertical div") - - cy.get("#scroll-into-view-vertical div").scrollIntoView().then ($div) -> - expect($div).to.match div - - it "scrolls x axis of window to element", -> - expect(@win.scrollY).to.eq(0) - expect(@win.scrollX).to.eq(0) - - cy.get("#scroll-into-view-win-horizontal div").scrollIntoView() - cy.window().then (win) -> - expect(win.scrollY).to.eq(0) - expect(win.scrollX).not.to.eq(0) - - it "scrolls y axis of window to element", -> - expect(@win.scrollY).to.eq(0) - expect(@win.scrollX).to.eq(0) - - cy.get("#scroll-into-view-win-vertical div").scrollIntoView() - cy.window().then (win) -> - expect(win.pageYOffset).not.to.eq(0) - expect(Math.floor(win.pageXOffset)).closeTo(200, 2) - - it "scrolls both axes of window to element", -> - expect(@win.scrollY).to.eq(0) - expect(@win.scrollX).to.eq(0) - - cy.get("#scroll-into-view-win-both div").scrollIntoView() - cy.window().then (win) -> - expect(win.scrollY).not.to.eq(0) - expect(win.scrollX).not.to.eq(0) - - it "scrolls x axis of container to element", -> - expect(@scrollHoriz.get(0).scrollTop).to.eq(0) - expect(@scrollHoriz.get(0).scrollLeft).to.eq(0) - - cy.get("#scroll-into-view-horizontal h5").scrollIntoView().then ($el) -> - expect(@scrollHoriz.get(0).scrollTop).to.eq(0) - expect(@scrollHoriz.get(0).scrollLeft).to.eq(300) - - it "scrolls y axis of container to element", -> - expect(@scrollVert.get(0).scrollTop).to.eq(0) - expect(@scrollVert.get(0).scrollLeft).to.eq(0) - - cy.get("#scroll-into-view-vertical h5").scrollIntoView().then ($el) -> - expect(@scrollVert.get(0).scrollTop).to.eq(300) - expect(@scrollVert.get(0).scrollLeft).to.eq(0) - - it "scrolls both axes of container to element", -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) - - cy.get("#scroll-into-view-both h5").scrollIntoView().then ($el) -> - expect(@scrollBoth.get(0).scrollTop).to.eq(300) - expect(@scrollBoth.get(0).scrollLeft).to.eq(300) - - it "calls jQuery scroll to", -> - scrollTo = cy.spy($.fn, "scrollTo") - - cy.get("#scroll-into-view-both h5").scrollIntoView().then -> - expect(scrollTo).to.be.called - - it "sets duration to 0 by default", -> - scrollTo = cy.spy($.fn, "scrollTo") - - cy.get("#scroll-into-view-both h5").scrollIntoView().then -> - expect(scrollTo).to.be.calledWithMatch({}, {duration: 0}) - - it "sets axis to correct x or y", -> - scrollTo = cy.spy($.fn, "scrollTo") - - cy.get("#scroll-into-view-both h5").scrollIntoView().then -> - expect(scrollTo).to.be.calledWithMatch({}, {axis: "xy"}) - - it "scrolling resolves after a set duration", -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) - - scrollTo = cy.spy($.fn, "scrollTo") - - cy.get("#scroll-into-view-both h5").scrollIntoView({duration: 500}).then -> - expect(scrollTo).to.be.calledWithMatch({}, {duration: 500}) - expect(@scrollBoth.get(0).scrollLeft).to.eq(300) - expect(@scrollBoth.get(0).scrollTop).to.eq(300) - - it "accepts duration string option", -> - scrollTo = cy.spy($.fn, "scrollTo") - - cy.get("#scroll-into-view-both h5").scrollIntoView({duration: "500"}).then -> - expect(scrollTo.args[0][1].duration).to.eq "500" - - it "accepts offset string option", -> - scrollTo = cy.spy($.fn, "scrollTo") - - cy.get("#scroll-into-view-both h5").scrollIntoView({offset: 500}).then -> - expect(scrollTo.args[0][1].offset).to.eq 500 - - it "accepts offset object option", -> - scrollTo = cy.spy($.fn, "scrollTo") - - cy.get("#scroll-into-view-both h5").scrollIntoView({offset: {left: 500, top: 200}}).then -> - expect(scrollTo.args[0][1].offset).to.deep.eq {left: 500, top: 200} - - it "has easing set to swing by default", -> - scrollTo = cy.spy($.fn, "scrollTo") - - cy.get("#scroll-into-view-both h5").scrollIntoView().then -> - expect(scrollTo.args[0][1].easing).to.eq "swing" - - it "scrolling resolves after easing", -> - expect(@scrollBoth.get(0).scrollTop).to.eq(0) - expect(@scrollBoth.get(0).scrollLeft).to.eq(0) - - scrollTo = cy.spy($.fn, "scrollTo") - - cy.get("#scroll-into-view-both h5").scrollIntoView({easing: "linear"}).then -> - expect(scrollTo).to.be.calledWithMatch({}, {easing: "linear"}) - expect(@scrollBoth.get(0).scrollTop).to.eq(300) - expect(@scrollBoth.get(0).scrollLeft).to.eq(300) - - describe "assertion verification", -> - beforeEach -> - cy.on "log:added", (attrs, log) => - if log.get("name") is "assert" - @lastLog = log - - return null - - it "eventually passes the assertion", -> - cy.on "command:retry", _.after 2, -> - cy.$$("#scroll-into-view-win-vertical div").addClass("scrolled") - - cy + return cy .contains("scroll into view vertical") .scrollIntoView() - .should("have.class", "scrolled").then -> - lastLog = @lastLog - - expect(lastLog.get("name")).to.eq("assert") - expect(lastLog.get("state")).to.eq("passed") - expect(lastLog.get("ended")).to.be.true - - describe "errors", -> - beforeEach -> - Cypress.config("defaultCommandTimeout", 50) - - @logs = [] - - cy.on "log:added", (attrs, log) => - @lastLog = log - @logs.push(log) - - return null - - context "subject errors", -> - it "throws when not passed DOM element as subject", (done) -> - cy.on "fail", (err) => - expect(err.message).to.include "`cy.scrollIntoView()` failed because it requires a DOM element." - expect(err.message).to.include "{foo: bar}" - expect(err.message).to.include "> `cy.noop()`" - done() - - cy.noop({foo: "bar"}).scrollIntoView() - - it "throws when passed window object as subject", (done) -> - cy.on "fail", (err) => - expect(err.message).to.include "`cy.scrollIntoView()` failed because it requires a DOM element." - expect(err.message).to.include "" - expect(err.message).to.include "> `cy.window()`" - done() - - cy.window().scrollIntoView() - - it "throws when passed document object as subject", (done) -> - cy.on "fail", (err) => - expect(err.message).to.include "`cy.scrollIntoView()` failed because it requires a DOM element." - expect(err.message).to.include "" - expect(err.message).to.include "> `cy.document()`" - done() - - cy.document().scrollIntoView() - - it "throws if scrollable container is multiple elements", (done) -> - cy.on "fail", (err) => - expect(err.message).to.include "`cy.scrollIntoView()` can only be used to scroll to 1 element, you tried to scroll to 2 elements." - expect(err.docsUrl).to.include("https://on.cypress.io/scrollintoview") - done() - - cy.get("button").scrollIntoView() - - context "argument errors", -> - it "throws if arg passed as non-object", (done) -> - cy.on "fail", (err) => - expect(err.message).to.include "`cy.scrollIntoView()` can only be called with an `options` object. Your argument was: `foo`" - expect(err.docsUrl).to.eq("https://on.cypress.io/scrollintoview") - done() - - cy.get("#scroll-into-view-both h5").scrollIntoView("foo") - - context "option errors", -> - it "throws if duration is not a number or valid string", (done) -> - cy.on "fail", (err) => - expect(err.message).to.include "`cy.scrollIntoView()` must be called with a valid `duration`. Duration may be either a number (ms) or a string representing a number (ms). Your duration was: `foo`" - expect(err.docsUrl).to.include("https://on.cypress.io/scrollintoview") - done() - - cy.get("#scroll-into-view-both h5").scrollIntoView({ duration: "foo" }) - - it "throws if unrecognized easing", (done) -> - cy.on "fail", (err) => - expect(err.message).to.include "`cy.scrollIntoView()` must be called with a valid `easing`. Your easing was: `flower`" - expect(err.docsUrl).to.include("https://on.cypress.io/scrollintoview") - done() - - cy.get("#scroll-into-view-both h5").scrollIntoView({ easing: "flower" }) - - describe ".log", -> - beforeEach -> - @logs = [] - - cy.on "log:added", (attrs, log) => - @lastLog = log - @logs.push(log) - - return null - - it "logs out scrollIntoView", -> - cy.get("#scroll-into-view-both h5").scrollIntoView().then -> - lastLog = @lastLog - - expect(lastLog.get("name")).to.eq "scrollIntoView" - - it "passes in $el", -> - cy.get("#scroll-into-view-both h5").scrollIntoView().then ($container) -> - lastLog = @lastLog - - expect(lastLog.get("$el").get(0)).to.eq $container.get(0) - - it "logs duration options", -> - cy.get("#scroll-into-view-both h5").scrollIntoView({duration: "1"}).then -> - lastLog = @lastLog - - expect(lastLog.get("message")).to.eq "{duration: 1}" - - it "logs easing options", -> - cy.get("#scroll-into-view-both h5").scrollIntoView({easing: "linear"}).then -> - lastLog = @lastLog - - expect(lastLog.get("message")).to.eq "{easing: linear}" - - it "logs offset options", -> - cy.get("#scroll-into-view-both h5").scrollIntoView({offset: {left: 500, top: 200}}).then -> - lastLog = @lastLog - - expect(lastLog.get("message")).to.eq "{offset: {left: 500, top: 200}}" - - it "snapshots immediately", -> - cy.get("#scroll-into-view-both h5").scrollIntoView().then -> - lastLog = @lastLog - - expect(lastLog.get("snapshots").length).to.eq(1) - expect(lastLog.get("snapshots")[0]).to.be.an("object") - - it "#consoleProps", -> - cy.get("#scroll-into-view-both h5").scrollIntoView().then ($container) -> - console = @lastLog.invoke("consoleProps") - expect(console.Command).to.eq("scrollIntoView") - expect(console["Applied To"]).to.eq $container.get(0) - expect(console["Scrolled Element"]).to.exist + .should("have.class", "scrolled").then(function() { + const { + lastLog + } = this; + + expect(lastLog.get("name")).to.eq("assert"); + expect(lastLog.get("state")).to.eq("passed"); + return expect(lastLog.get("ended")).to.be.true; + }); + }); + }); + + describe("errors", function() { + beforeEach(function() { + Cypress.config("defaultCommandTimeout", 50); + + this.logs = []; + + cy.on("log:added", (attrs, log) => { + this.lastLog = log; + return this.logs.push(log); + }); + + return null; + }); + + context("subject errors", function() { + it("throws when not passed DOM element as subject", function(done) { + cy.on("fail", err => { + expect(err.message).to.include("`cy.scrollIntoView()` failed because it requires a DOM element."); + expect(err.message).to.include("{foo: bar}"); + expect(err.message).to.include("> `cy.noop()`"); + return done(); + }); + + return cy.noop({foo: "bar"}).scrollIntoView(); + }); + + it("throws when passed window object as subject", function(done) { + cy.on("fail", err => { + expect(err.message).to.include("`cy.scrollIntoView()` failed because it requires a DOM element."); + expect(err.message).to.include(""); + expect(err.message).to.include("> `cy.window()`"); + return done(); + }); + + return cy.window().scrollIntoView(); + }); + + it("throws when passed document object as subject", function(done) { + cy.on("fail", err => { + expect(err.message).to.include("`cy.scrollIntoView()` failed because it requires a DOM element."); + expect(err.message).to.include(""); + expect(err.message).to.include("> `cy.document()`"); + return done(); + }); + + return cy.document().scrollIntoView(); + }); + + return it("throws if scrollable container is multiple elements", function(done) { + cy.on("fail", err => { + expect(err.message).to.include("`cy.scrollIntoView()` can only be used to scroll to 1 element, you tried to scroll to 2 elements."); + expect(err.docsUrl).to.include("https://on.cypress.io/scrollintoview"); + return done(); + }); + + return cy.get("button").scrollIntoView(); + }); + }); + + context("argument errors", () => it("throws if arg passed as non-object", function(done) { + cy.on("fail", err => { + expect(err.message).to.include("`cy.scrollIntoView()` can only be called with an `options` object. Your argument was: `foo`"); + expect(err.docsUrl).to.eq("https://on.cypress.io/scrollintoview"); + return done(); + }); + + return cy.get("#scroll-into-view-both h5").scrollIntoView("foo"); + })); + + return context("option errors", function() { + it("throws if duration is not a number or valid string", function(done) { + cy.on("fail", err => { + expect(err.message).to.include("`cy.scrollIntoView()` must be called with a valid `duration`. Duration may be either a number (ms) or a string representing a number (ms). Your duration was: `foo`"); + expect(err.docsUrl).to.include("https://on.cypress.io/scrollintoview"); + return done(); + }); + + return cy.get("#scroll-into-view-both h5").scrollIntoView({ duration: "foo" }); + }); + + return it("throws if unrecognized easing", function(done) { + cy.on("fail", err => { + expect(err.message).to.include("`cy.scrollIntoView()` must be called with a valid `easing`. Your easing was: `flower`"); + expect(err.docsUrl).to.include("https://on.cypress.io/scrollintoview"); + return done(); + }); + + return cy.get("#scroll-into-view-both h5").scrollIntoView({ easing: "flower" }); + }); + }); + }); + + return describe(".log", function() { + beforeEach(function() { + this.logs = []; + + cy.on("log:added", (attrs, log) => { + this.lastLog = log; + return this.logs.push(log); + }); + + return null; + }); + + it("logs out scrollIntoView", () => cy.get("#scroll-into-view-both h5").scrollIntoView().then(function() { + const { + lastLog + } = this; + + return expect(lastLog.get("name")).to.eq("scrollIntoView"); + })); + + it("passes in $el", () => cy.get("#scroll-into-view-both h5").scrollIntoView().then(function($container) { + const { + lastLog + } = this; + + return expect(lastLog.get("$el").get(0)).to.eq($container.get(0)); + })); + + it("logs duration options", () => cy.get("#scroll-into-view-both h5").scrollIntoView({duration: "1"}).then(function() { + const { + lastLog + } = this; + + return expect(lastLog.get("message")).to.eq("{duration: 1}"); + })); + + it("logs easing options", () => cy.get("#scroll-into-view-both h5").scrollIntoView({easing: "linear"}).then(function() { + const { + lastLog + } = this; + + return expect(lastLog.get("message")).to.eq("{easing: linear}"); + })); + + it("logs offset options", () => cy.get("#scroll-into-view-both h5").scrollIntoView({offset: {left: 500, top: 200}}).then(function() { + const { + lastLog + } = this; + + return expect(lastLog.get("message")).to.eq("{offset: {left: 500, top: 200}}"); + })); + + it("snapshots immediately", () => cy.get("#scroll-into-view-both h5").scrollIntoView().then(function() { + const { + lastLog + } = this; + + expect(lastLog.get("snapshots").length).to.eq(1); + return expect(lastLog.get("snapshots")[0]).to.be.an("object"); + })); + + return it("#consoleProps", () => cy.get("#scroll-into-view-both h5").scrollIntoView().then(function($container) { + const console = this.lastLog.invoke("consoleProps"); + expect(console.Command).to.eq("scrollIntoView"); + expect(console["Applied To"]).to.eq($container.get(0)); + return expect(console["Scrolled Element"]).to.exist; + })); + }); + }); +}); diff --git a/packages/driver/test/cypress/integration/commands/actions/select_spec.js b/packages/driver/test/cypress/integration/commands/actions/select_spec.js index 719d3c064bca..48461f9c72b2 100644 --- a/packages/driver/test/cypress/integration/commands/actions/select_spec.js +++ b/packages/driver/test/cypress/integration/commands/actions/select_spec.js @@ -1,434 +1,516 @@ -$ = Cypress.$.bind(Cypress) -_ = Cypress._ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const $ = Cypress.$.bind(Cypress); +const { + _ +} = Cypress; -describe "src/cy/commands/actions/select", -> - before -> - cy - .visit("/fixtures/dom.html") - .then (win) -> - @body = win.document.body.outerHTML +describe("src/cy/commands/actions/select", function() { + before(() => cy + .visit("/fixtures/dom.html") + .then(function(win) { + return this.body = win.document.body.outerHTML; + })); - beforeEach -> - doc = cy.state("document") + beforeEach(function() { + const doc = cy.state("document"); - $(doc.body).empty().html(@body) + return $(doc.body).empty().html(this.body); + }); - context "#select", -> - it "does not change the subject", -> - select = cy.$$("select[name=maps]") + return context("#select", function() { + it("does not change the subject", function() { + const select = cy.$$("select[name=maps]"); - cy.get("select[name=maps]").select("train").then ($select) -> - expect($select).to.match select + return cy.get("select[name=maps]").select("train").then($select => expect($select).to.match(select)); + }); - it "selects by value", -> - cy.get("select[name=maps]").select("de_train").then ($select) -> - expect($select).to.have.value("de_train") + it("selects by value", () => cy.get("select[name=maps]").select("de_train").then($select => expect($select).to.have.value("de_train"))); - it "selects by text", -> - cy.get("select[name=maps]").select("train").then ($select) -> - expect($select).to.have.value("de_train") + it("selects by text", () => cy.get("select[name=maps]").select("train").then($select => expect($select).to.have.value("de_train"))); - it "selects by trimmed text with newlines stripped", -> - cy.get("select[name=maps]").select("italy").then ($select) -> - expect($select).to.have.value("cs_italy") + it("selects by trimmed text with newlines stripped", () => cy.get("select[name=maps]").select("italy").then($select => expect($select).to.have.value("cs_italy"))); - it "prioritizes value over text", -> - cy.get("select[name=foods]").select("Ramen").then ($select) -> - expect($select).to.have.value("Ramen") + it("prioritizes value over text", () => cy.get("select[name=foods]").select("Ramen").then($select => expect($select).to.have.value("Ramen"))); - it "can select an array of values", -> - cy.get("select[name=movies]").select(["apoc", "br"]).then ($select) -> - expect($select.val()).to.deep.eq ["apoc", "br"] + it("can select an array of values", () => cy.get("select[name=movies]").select(["apoc", "br"]).then($select => expect($select.val()).to.deep.eq(["apoc", "br"]))); - it "can handle options nested in optgroups", -> - cy.get("select[name=starwars]").select("Jar Jar").then ($select) -> - expect($select).to.have.value("jarjar") + it("can handle options nested in optgroups", () => cy.get("select[name=starwars]").select("Jar Jar").then($select => expect($select).to.have.value("jarjar"))); - it "can handle options with same value selected by text", -> - cy.get("select[name=startrek-same]").select("Uhura").then ($select) -> - expect($select.val()).to.equal("same") - expect($select.find("option:selected")).to.have.text("Uhura") - expect($select[0].selectedIndex).to.equal(2) - expect($select[0].selectedOptions[0]).to.eql($select.find("option:selected")[0]) + it("can handle options with same value selected by text", () => cy.get("select[name=startrek-same]").select("Uhura").then(function($select) { + expect($select.val()).to.equal("same"); + expect($select.find("option:selected")).to.have.text("Uhura"); + expect($select[0].selectedIndex).to.equal(2); + return expect($select[0].selectedOptions[0]).to.eql($select.find("option:selected")[0]); + })); - it "can handle options with some same values selected by text", -> - cy.get("select[name=startrek-some-same]").select("Uhura").then ($select) -> - expect($select.val()).to.equal("same") - expect($select.find("option:selected")).to.have.text("Uhura") - expect($select[0].selectedIndex).to.equal(2) - expect($select[0].selectedOptions[0]).to.eql($select.find("option:selected")[0]) + it("can handle options with some same values selected by text", () => cy.get("select[name=startrek-some-same]").select("Uhura").then(function($select) { + expect($select.val()).to.equal("same"); + expect($select.find("option:selected")).to.have.text("Uhura"); + expect($select[0].selectedIndex).to.equal(2); + return expect($select[0].selectedOptions[0]).to.eql($select.find("option:selected")[0]); + })); - it "can select an array of values", -> - cy.get("select[name=movies]").select(["apoc", "br"]).then ($select) -> - expect($select.val()).to.deep.eq ["apoc", "br"] + it("can select an array of values", () => cy.get("select[name=movies]").select(["apoc", "br"]).then($select => expect($select.val()).to.deep.eq(["apoc", "br"]))); - it "can select an array of texts", -> - cy.get("select[name=movies]").select(["The Human Condition", "There Will Be Blood"]).then ($select) -> - expect($select.val()).to.deep.eq ["thc", "twbb"] + it("can select an array of texts", () => cy.get("select[name=movies]").select(["The Human Condition", "There Will Be Blood"]).then($select => expect($select.val()).to.deep.eq(["thc", "twbb"]))); - ## readonly should only be limited to inputs, not checkboxes - it "can select a readonly select", -> - cy.get("select[name=hunter]").select("gon").then ($select) -> - expect($select.val()).to.eq("gon-val") + //# readonly should only be limited to inputs, not checkboxes + it("can select a readonly select", () => cy.get("select[name=hunter]").select("gon").then($select => expect($select.val()).to.eq("gon-val"))); - it "clears previous values when providing an array", -> - ## make sure we have a previous value - select = cy.$$("select[name=movies]").val(["2001"]) - expect(select.val()).to.deep.eq ["2001"] + it("clears previous values when providing an array", function() { + //# make sure we have a previous value + const select = cy.$$("select[name=movies]").val(["2001"]); + expect(select.val()).to.deep.eq(["2001"]); - cy.get("select[name=movies]").select(["apoc", "br"]).then ($select) -> - expect($select.val()).to.deep.eq ["apoc", "br"] + return cy.get("select[name=movies]").select(["apoc", "br"]).then($select => expect($select.val()).to.deep.eq(["apoc", "br"])); + }); - it "lists the select as the focused element", -> - select = cy.$$("#select-maps") + it("lists the select as the focused element", function() { + const select = cy.$$("#select-maps"); - cy.get("#select-maps").select("de_train").focused().then ($focused) -> - expect($focused.get(0)).to.eq select.get(0) + return cy.get("#select-maps").select("de_train").focused().then($focused => expect($focused.get(0)).to.eq(select.get(0))); + }); - it "causes previous input to receive blur", (done) -> - cy.$$("input:text:first").blur -> done() + it("causes previous input to receive blur", function(done) { + cy.$$("input:text:first").blur(() => done()); - cy.get("input:text:first").type("foo") - cy.get("#select-maps").select("de_train") + cy.get("input:text:first").type("foo"); + return cy.get("#select-maps").select("de_train"); + }); - it "can forcibly click even when being covered by another element", (done) -> - select = $("").attr("id", "select-covered-in-span").prependTo(cy.$$("body")) - span = $("span on select").css(position: "absolute", left: select.offset().left, top: select.offset().top, padding: 5, display: "inline-block", backgroundColor: "yellow").prependTo(cy.$$("body")) + it("can forcibly click even when being covered by another element", function(done) { + const select = $("").attr("id", "select-covered-in-span").prependTo(cy.$$("body")); + const span = $("span on select").css({position: "absolute", left: select.offset().left, top: select.offset().top, padding: 5, display: "inline-block", backgroundColor: "yellow"}).prependTo(cy.$$("body")); - select.on "click", -> done() + select.on("click", () => done()); - cy.get("#select-covered-in-span").select("foo", {force: true}) + return cy.get("#select-covered-in-span").select("foo", {force: true}); + }); - it "passes timeout and interval down to click", (done) -> - select = $("").attr("id", "select-covered-in-span").prependTo(cy.$$("body")); + const span = $("span on select").css({position: "absolute", left: select.offset().left, top: select.offset().top, padding: 5, display: "inline-block", backgroundColor: "yellow"}).prependTo(cy.$$("body")); - cy.on "command:retry", (options) -> - expect(options.timeout).to.eq 1000 - expect(options.interval).to.eq 60 - done() + cy.on("command:retry", function(options) { + expect(options.timeout).to.eq(1000); + expect(options.interval).to.eq(60); + return done(); + }); - cy.get("#select-covered-in-span").select("foobar", {timeout: 1000, interval: 60}) + return cy.get("#select-covered-in-span").select("foobar", {timeout: 1000, interval: 60}); + }); - it "can forcibly click even when element is invisible", (done) -> - select = cy.$$("#select-maps").hide() + it("can forcibly click even when element is invisible", function(done) { + const select = cy.$$("#select-maps").hide(); - select.click -> done() + select.click(() => done()); - cy.get("#select-maps").select("de_dust2", {force: true}) + return cy.get("#select-maps").select("de_dust2", {force: true}); + }); - it "can forcibly click when select is disabled", () -> + it("can forcibly click when select is disabled", function() { cy.get("select[name=disabled]") - ## default select value - .invoke("val").should("eq", "foo") + //# default select value + .invoke("val").should("eq", "foo"); - cy.get("select[name=disabled]") + return cy.get("select[name=disabled]") .select("bar", { force: true }) - .invoke("val").should("eq", "bar") - - it "retries until ") - - cy.on "command:retry", _.once => - cy.$$("#select-maps").append option - - cy.get("#select-maps").select("foo") - - it "retries until `. Your subject contained #{num} elements." - expect(err.docsUrl).to.eq("https://on.cypress.io/select") - done() - - cy.get("select").select("foo") - - it "throws on anything other than a select", (done) -> - cy.on "fail", (err) -> - expect(err.message).to.include "`cy.select()` can only be called on a ``" - expect(err.docsUrl).to.eq("https://on.cypress.io/select") - done() - - cy.get("input:first").select("foo") - - it "throws when finding duplicate values", (done) -> - cy.on "fail", (err) -> - expect(err.message).to.include "`cy.select()` matched more than one `option` by value or text: `bm`" - expect(err.docsUrl).to.eq("https://on.cypress.io/select") - done() - - cy.get("select[name=names]").select("bm") - - it "throws when passing an array to a non multiple select", (done) -> - cy.on "fail", (err) -> - expect(err.message).to.include "`cy.select()` was called with an array of arguments but does not have a `multiple` attribute set." - expect(err.docsUrl).to.eq("https://on.cypress.io/select") - done() - - cy.get("select[name=names]").select(["bm", "ss"]) - - it "throws when the subject isnt visible", (done) -> - select = cy.$$("#select-maps").show().hide() - - cy.on "fail", (err) -> - expect(err.message).to.include "`cy.select()` failed because this element is not visible" - done() - - cy.get("#select-maps").select("de_dust2") - - it "throws when value or text does not exist", (done) -> - cy.on "fail", (err) -> - expect(err.message).to.include("`cy.select()` failed because it could not find a single ` is no longer disabled", function() { + const select = cy.$$("select[name=optgroup-disabled]"); - expect(lastLog.get("state")).to.eq("pending") - done() + cy.on("command:retry", _.once(() => { + return select.find("optgroup").prop("disabled", false); + }) + ); - cy.get("#select-maps").select("de_dust2") + return cy.get("select[name=optgroup-disabled]").select("bar") + .invoke("val").should("eq", "bar"); + }); - it "ends", -> - cy.get("#select-maps").select("de_dust2").then -> - lastLog = @lastLog + it("retries until are no longer disabled", function() { + const select = cy.$$("select[name=opt-disabled]"); - expect(lastLog.get("state")).to.eq("passed") + cy.on("command:retry", _.once(() => { + return select.find("option").prop("disabled", false); + }) + ); - it "#consoleProps", -> - cy.get("#select-maps").select("de_dust2").then ($select) -> - { fromElWindow } = Cypress.dom.getElementCoordinatesByPosition($select) - console = @lastLog.invoke("consoleProps") - expect(console.Command).to.eq("select") - expect(console.Selected).to.deep.eq ["de_dust2"] - expect(console["Applied To"]).to.eq $select.get(0) - expect(console.Coords.x).to.be.closeTo(fromElWindow.x, 10) - expect(console.Coords.y).to.be.closeTo(fromElWindow.y, 10) + return cy.get("select[name=opt-disabled]").select("bar") + .invoke("val").should("eq", "bar"); + }); - it "logs only one select event", -> - types = [] + describe("assertion verification", function() { + beforeEach(function() { + cy.on("log:added", (attrs, log) => { + if (log.get("name") === "assert") { + return this.lastLog = log; + } + }); - cy.on "log:added", (attrs, log) -> - if log.get("name") is "select" - types.push(log) + return null; + }); - cy.get("#select-maps").select("de_dust2").then -> - expect(@logs.length).to.eq(2) - expect(types.length).to.eq(1) + return it("eventually passes the assertion", function() { + cy.$$("#select-maps").change(function() { + return _.delay(() => { + return $(this).addClass("selected"); + } + , 100); + }); - it "logs deltaOptions", -> - cy.get("#select-maps").select("de_dust2", {force: true, timeout: 1000}).then -> - lastLog = @lastLog + return cy.get("#select-maps").select("de_nuke").should("have.class", "selected").then(function() { + const { + lastLog + } = this; - expect(lastLog.get("message")).to.eq "{force: true, timeout: 1000}" - expect(lastLog.invoke("consoleProps").Options).to.deep.eq {force: true, timeout: 1000} + expect(lastLog.get("name")).to.eq("assert"); + expect(lastLog.get("state")).to.eq("passed"); + return expect(lastLog.get("ended")).to.be.true; + }); + }); + }); + + describe("events", function() { + it("emits click event", function(done) { + cy.$$("select[name=maps]").click(() => done()); + + return cy.get("select[name=maps]").select("train"); + }); + + it("emits change event", function(done) { + cy.$$("select[name=maps]").change(() => done()); + + return cy.get("select[name=maps]").select("train"); + }); + + it("emits focus event", function(done) { + cy.$$("select[name=maps]").one("focus", () => done()); + + return cy.get("select[name=maps]").select("train"); + }); + + it("emits input event", function(done) { + cy.$$("select[name=maps]").one("input", () => done()); + + return cy.get("select[name=maps]").select("train"); + }); + + return it("emits all events in the correct order", function() { + const fired = []; + const events = ["mousedown", "focus", "mouseup", "click", "input", "change"]; + + _.each(events, event => { + return cy.$$("select[name=maps]").one(event, () => fired.push(event)); + }); + + return cy.get("select[name=maps]").select("train").then(() => expect(fired).to.deep.eq(events)); + }); + }); + + describe("errors", function() { + beforeEach(function() { + Cypress.config("defaultCommandTimeout", 100); + + this.logs = []; + + cy.on("log:added", (attrs, log) => { + this.lastLog = log; + return this.logs.push(log); + }); + + return null; + }); + + it("throws when not a dom subject", function(done) { + cy.on("fail", () => done()); + + return cy.noop({}).select("foo"); + }); + + it("throws when subject is not in the document", function(done) { + let selected = 0; + + var $select = cy.$$("#select-maps").change(function(e) { + selected += 1; + return $select.remove(); + }); + + cy.on("fail", function(err) { + expect(selected).to.eq(1); + expect(err.message).to.include("`cy.select()` failed because this element"); + return done(); + }); + + return cy.get("#select-maps").select("de_dust2").select("de_aztec"); + }); + + it("throws when more than 1 element in the collection", function(done) { + const num = cy.$$("select").length; + + cy.on("fail", err => { + expect(err.message).to.include(`\`cy.select()\` can only be called on a single \``. Your subject is a: ``"); + expect(err.docsUrl).to.eq("https://on.cypress.io/select"); + return done(); + }); + + return cy.get("input:first").select("foo"); + }); + + it("throws when finding duplicate values", function(done) { + cy.on("fail", function(err) { + expect(err.message).to.include("`cy.select()` matched more than one `option` by value or text: `bm`"); + expect(err.docsUrl).to.eq("https://on.cypress.io/select"); + return done(); + }); + + return cy.get("select[name=names]").select("bm"); + }); + + it("throws when passing an array to a non multiple select", function(done) { + cy.on("fail", function(err) { + expect(err.message).to.include("`cy.select()` was called with an array of arguments but does not have a `multiple` attribute set."); + expect(err.docsUrl).to.eq("https://on.cypress.io/select"); + return done(); + }); + + return cy.get("select[name=names]").select(["bm", "ss"]); + }); + + it("throws when the subject isnt visible", function(done) { + const select = cy.$$("#select-maps").show().hide(); + + cy.on("fail", function(err) { + expect(err.message).to.include("`cy.select()` failed because this element is not visible"); + return done(); + }); + + return cy.get("#select-maps").select("de_dust2"); + }); + + it("throws when value or text does not exist", function(done) { + cy.on("fail", function(err) { + expect(err.message).to.include("`cy.select()` failed because it could not find a single `