UNPKG

@revoloo/cypress6

Version:

Cypress.io end to end testing tool

1,033 lines (783 loc) 26.8 kB
const { _, $ } = Cypress describe('src/cy/commands/window', () => { context('#window', () => { it('returns the remote window', () => { cy.window().then((win) => { expect(win).to.eq(cy.state('$autIframe').prop('contentWindow')) }) }) describe('assertion verification', { defaultCommandTimeout: 100, }, () => { beforeEach(function () { this.remoteWindow = cy.state('window') delete this.remoteWindow.foo this.logs = [] cy.on('log:added', (attrs, log) => { this.lastLog = log this.logs.push(log) }) return null }) it('eventually passes the assertion', function () { cy.on('command:retry', _.after(2, () => { this.remoteWindow.foo = 'bar' })) cy.window().should('have.property', 'foo', 'bar').then(function () { const { lastLog } = this expect(lastLog.get('name')).to.eq('assert') expect(lastLog.get('state')).to.eq('passed') expect(lastLog.get('ended')).to.be.true }) }) it('eventually fails the assertion', function (done) { cy.on('command:retry', _.after(2, () => { this.remoteWindow.foo = 'foo' })) 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) done() }) cy.window().should('have.property', 'foo', 'bar') }) it('can still fail on window', function (done) { const win = cy.state('window') cy.state('window', undefined) cy.on('fail', (err) => { cy.state('window', win) const { lastLog } = this expect(this.logs.length).to.eq(1) expect(err.message).to.include(lastLog.get('error').message) expect(lastLog.get('name')).to.eq('window') expect(lastLog.get('state')).to.eq('failed') done() }) cy.window() }) it('does not log an additional log on failure', function (done) { this.remoteWindow.foo = 'foo' cy.on('fail', () => { expect(this.logs.length).to.eq(2) done() }) cy.window().should('have.property', 'foo', 'bar') }) }) describe('.log', () => { beforeEach(function () { this.logs = [] cy.on('log:added', (attrs, log) => { this.lastLog = log this.logs.push(log) }) return null }) it('can turn off logging', () => { cy.window({ log: false }).then(function () { expect(this.log).to.be.undefined }) }) it('logs immediately before resolving', (done) => { cy.on('log:added', (attrs, log) => { if (attrs.name === 'window') { expect(log.get('state')).to.eq('pending') expect(log.get('snapshot')).not.to.be.ok done() } }) cy.window() }) it('snapshots after resolving', () => { cy.window().then(function () { const { lastLog } = this expect(lastLog.get('snapshots').length).to.eq(1) expect(lastLog.get('snapshots')[0]).to.be.an('object') }) }) it('can be aliased', () => { return cy .window().as('win') .get('body') .get('@win').then(function (win) { // window + get + get expect(this.logs.length).to.eq(3) expect(win).to.eq(this.win) expect(this.logs[0].get('alias')).to.eq('win') expect(this.logs[0].get('aliasType')).to.eq('primitive') expect(this.logs[2].get('aliasType')).to.eq('primitive') expect(this.logs[2].get('referencesAlias').name).to.eq('win') }) }) it('logs obj', () => { cy.window().then(function () { const obj = { name: 'window', message: '', } const { lastLog } = this _.each(obj, (value, key) => { expect(lastLog.get(key)).to.deep.eq(value) }) }) }) it('#consoleProps', () => { cy.window().then(function (win) { expect(this.lastLog.invoke('consoleProps')).to.deep.eq({ Command: 'window', Yielded: win, }) }) }) }) }) context('#document', () => { it('returns the remote document as a jquery object', () => { cy.document().then(($doc) => { expect($doc).to.eq(cy.state('$autIframe').prop('contentDocument')) }) }) describe('assertion verification', { defaultCommandTimeout: 100, }, () => { beforeEach(function () { this.remoteDocument = cy.state('window').document delete this.remoteDocument.foo this.logs = [] cy.on('log:added', (attrs, log) => { this.lastLog = log this.logs.push(log) }) return null }) it('eventually passes the assertion', function () { cy.on('command:retry', _.after(2, () => { this.remoteDocument.foo = 'bar' })) cy.document().should('have.property', 'foo', 'bar').then(function () { const { lastLog } = this expect(lastLog.get('name')).to.eq('assert') expect(lastLog.get('state')).to.eq('passed') expect(lastLog.get('ended')).to.be.true }) }) it('eventually fails the assertion', function (done) { cy.on('command:retry', _.after(2, () => { this.remoteDocument.foo = 'foo' })) 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) done() }) cy.document().should('have.property', 'foo', 'bar') }) it('can still fail on document', function (done) { const win = cy.state('window') cy.state('window', undefined) cy.on('fail', (err) => { cy.state('window', win) const { lastLog } = this expect(this.logs.length).to.eq(1) expect(err.message).to.include(lastLog.get('error').message) expect(lastLog.get('name')).to.eq('document') expect(lastLog.get('state')).to.eq('failed') done() }) cy.document() }) it('does not log an additional log on failure', function (done) { this.remoteDocument.foo = 'foo' cy.on('fail', () => { expect(this.logs.length).to.eq(2) done() }) cy.document().should('have.property', 'foo', 'bar') }) }) describe('.log', () => { beforeEach(function () { this.logs = [] cy.on('log:added', (attrs, log) => { this.lastLog = log this.logs.push(log) }) return null }) it('can turn off logging', () => { cy.document({ log: false }).then(function () { expect(this.log).to.be.undefined }) }) it('logs immediately before resolving', (done) => { cy.on('log:added', (attrs, log) => { if (attrs.name === 'document') { expect(log.get('state')).to.eq('pending') expect(log.get('snapshots')).not.to.be.ok done() } }) cy.document() }) it('snapshots after resolving', () => { cy.document().then(function () { const { lastLog } = this expect(lastLog.get('snapshots').length).to.eq(1) expect(lastLog.get('snapshots')[0]).to.be.an('object') }) }) it('can be aliased', function () { const logs = [] cy.on('log:added', (attrs, log) => { this.log = log logs.push(this.log) }) cy .document().as('doc') .get('body') .get('@doc').then(function (doc) { // docdow + get + get expect(this.logs.length).to.eq(3) expect(doc).to.eq(this.doc) expect(logs[0].get('alias')).to.eq('doc') expect(logs[0].get('aliasType')).to.eq('primitive') expect(logs[2].get('aliasType')).to.eq('primitive') expect(logs[2].get('referencesAlias').name).to.eq('doc') }) }) it('logs obj', () => { cy.document().then(function () { const obj = { name: 'document', message: '', } const { lastLog } = this _.each(obj, (value, key) => { expect(lastLog.get(key)).to.deep.eq(value) }) }) }) it('#consoleProps', () => { cy.document().then(function (win) { expect(this.lastLog.invoke('consoleProps')).to.deep.eq({ Command: 'document', Yielded: win, }) }) }) }) }) context('#title', () => { before(() => { cy .visit('/fixtures/generic.html') .then(function (win) { const h = $(win.document.head) h.find('script').remove() this.head = h.prop('outerHTML') this.body = win.document.body.outerHTML }) }) beforeEach(function () { const doc = cy.state('document') $(doc.head).empty().html(this.head) $(doc.body).empty().html(this.body) }) it('returns the pages title as a string', () => { const title = cy.$$('title').text() cy.title().then((text) => { expect(text).to.eq(title) }) }) it('retries finding the title', () => { cy.$$('title').remove() const retry = _.after(2, () => { cy.$$('head').append($('<title>waiting on title</title>')) }) cy.on('command:retry', retry) cy.title().should('eq', 'waiting on title') }) it('eventually resolves', () => { _.delay(() => { cy.$$('title').text('about page') }, 100) cy.title().should('eq', 'about page').and('match', /about/) }) it('uses the first title element', () => { cy.$$('head').prepend('<title>some title</title>') cy.$$('head').prepend('<title>another title</title>') cy.title().then(($title) => { expect($title).to.eq('another title') }) }) it('uses document.title setter over <title>', () => { const title = cy.$$('title') // make sure we have a title element expect(title.length).to.eq(1) expect(title.text()).not.to.eq('foo') cy.state('document').title = 'foo' cy.title().then((title) => { expect(title).to.eq('foo') }) }) it('is empty string when no <title>', () => { cy.$$('title').remove() cy.title().then(($title) => { expect($title).to.eq('') }) }) describe('errors', { defaultCommandTimeout: 50, }, () => { beforeEach(function () { this.logs = [] cy.on('log:added', (attrs, log) => { this.lastLog = log this.logs.push(log) }) return null }) it('throws after timing out', (done) => { cy.$$('title').remove() cy.on('fail', (err) => { expect(err.message).to.include('expected \'\' to equal \'asdf\'') done() }) cy.title().should('eq', 'asdf') }) it('only logs once', function (done) { cy.$$('title').remove() cy.on('fail', (err) => { const { lastLog } = this expect(this.logs.length).to.eq(2) expect(err.message).to.include(lastLog.get('error').message) done() }) cy.title().should('eq', 'asdf') }) }) describe('.log', () => { beforeEach(function () { cy.on('log:added', (attrs, log) => { this.lastLog = log if (log.get('name') === 'get') { throw new Error('`cy.get()` should not have logged out.') } }) return null }) it('can turn off logging', () => { cy.title({ log: false }).then(function () { expect(this.log).to.be.undefined }) }) it('logs immediately before resolving', (done) => { cy.on('log:added', (attrs, log) => { if (log.get('name') === 'title') { expect(log.get('state')).to.eq('pending') done() } }) cy.title() }) it('snapshots after clicking', () => { cy.title().then(function () { const { lastLog } = this expect(lastLog.get('snapshots').length).to.eq(1) expect(lastLog.get('snapshots')[0]).to.be.an('object') }) }) it('logs obj', () => { cy.title().then(function () { const obj = { name: 'title', } const { lastLog } = this _.each(obj, (value, key) => { expect(lastLog.get(key)).to.deep.eq(value) }) }) }) it('#consoleProps', () => { cy.title().then(function () { expect(this.lastLog.invoke('consoleProps')).to.deep.eq({ Command: 'title', Yielded: 'Generic HTML Fixture', }) }) }) }) }) context('#viewport', () => { it('triggers \'viewport:changed\' event with dimensions object', () => { let expected = false cy.on('viewport:changed', (viewport, fn) => { expected = true expect(viewport).to.deep.eq({ viewportWidth: 800, viewportHeight: 600 }) expect(fn).to.be.a('function') }) cy.viewport(800, 600).then(() => { expect(expected).to.be.true }) }) it('does not trigger \'viewport:changed\' when changing to the default', () => { const fn = function () { throw new Error('Should not trigger \'viewport:changed\'') } Cypress.prependListener('viewport:changed', fn) cy.viewport(1000, 660).then(() => { return Cypress.removeListener('viewport:changed', fn) }) }) it('does not trigger \'viewport:changed\' when changing to the same viewport', () => { let triggeredOnce = false const fn = function () { if (triggeredOnce) { throw new Error('Should not trigger \'viewport:changed\'') } triggeredOnce = true } Cypress.prependListener('viewport:changed', fn) cy.viewport(800, 600) cy.viewport(800, 600).then(() => { return Cypress.removeListener('viewport:changed', fn) }) }) it('triggers \'viewport:changed\' if width changes', (done) => { let finished = false setTimeout(() => { if (!finished) { return done('Timed out before \'viewport:changed\'') } }, 1000) let triggeredOnce = false cy.on('viewport:changed', (viewport) => { if (triggeredOnce) { expect(viewport).to.eql({ viewportWidth: 900, viewportHeight: 600 }) finished = true done() } triggeredOnce = true }) cy.viewport(800, 600) cy.viewport(900, 600) }) it('triggers \'viewport:changed\' if height changes', (done) => { let finished = false setTimeout(() => { if (!finished) { return done('Timed out before \'viewport:changed\'') } }, 1000) let triggeredOnce = false cy.on('viewport:changed', (viewport) => { if (triggeredOnce) { expect(viewport).to.eql({ viewportWidth: 800, viewportHeight: 700 }) finished = true done() } triggeredOnce = true }) cy.viewport(800, 600) cy.viewport(800, 700) }) it('sets subject to null', () => { cy.viewport('ipad-2').then((subject) => { expect(subject).to.be.null }) }) it('does not modify viewportWidth and viewportHeight in config', () => { let expected = false cy.on('viewport:changed', () => { expected = true expect(Cypress.config('viewportWidth')).not.to.eq(800) expect(Cypress.config('viewportHeight')).not.to.eq(600) }) cy.viewport(800, 600).then(() => { expect(expected).to.be.true }) }) context('changing viewport', () => { it('changes viewport and then resets back to the original', () => { const { viewportHeight, viewportWidth } = Cypress.config() cy.viewport(500, 400).then(() => { Cypress.action('runner:test:before:run:async', {}) .then(() => { expect(Cypress.config('viewportWidth')).to.eq(viewportWidth) expect(Cypress.config('viewportHeight')).to.eq(viewportHeight) }) }) }) }) context('presets', () => { it('ipad-2', (done) => { cy.on('viewport:changed', (viewport) => { expect(viewport).to.deep.eq({ viewportWidth: 768, viewportHeight: 1024 }) done() }) cy.viewport('ipad-2') }) it('ipad-mini', (done) => { cy.on('viewport:changed', (viewport) => { expect(viewport).to.deep.eq({ viewportWidth: 768, viewportHeight: 1024 }) done() }) cy.viewport('ipad-mini') }) it('iphone-xr', (done) => { cy.on('viewport:changed', (viewport) => { expect(viewport).to.deep.eq({ viewportWidth: 414, viewportHeight: 896 }) done() }) cy.viewport('iphone-xr') }) it('iphone-x', (done) => { cy.on('viewport:changed', (viewport) => { expect(viewport).to.deep.eq({ viewportWidth: 375, viewportHeight: 812 }) done() }) cy.viewport('iphone-x') }) it('iphone-6+', (done) => { cy.on('viewport:changed', (viewport) => { expect(viewport).to.deep.eq({ viewportWidth: 414, viewportHeight: 736 }) done() }) cy.viewport('iphone-6+') }) it('iphone-se2', (done) => { cy.on('viewport:changed', (viewport) => { expect(viewport).to.deep.eq({ viewportWidth: 375, viewportHeight: 667 }) done() }) cy.viewport('iphone-se2') }) it('iphone-8', (done) => { cy.on('viewport:changed', (viewport) => { expect(viewport).to.deep.eq({ viewportWidth: 375, viewportHeight: 667 }) done() }) cy.viewport('iphone-8') }) it('iphone-7', (done) => { cy.on('viewport:changed', (viewport) => { expect(viewport).to.deep.eq({ viewportWidth: 375, viewportHeight: 667 }) done() }) cy.viewport('iphone-7') }) it('iphone-6', (done) => { cy.on('viewport:changed', (viewport) => { expect(viewport).to.deep.eq({ viewportWidth: 375, viewportHeight: 667 }) done() }) cy.viewport('iphone-6') }) it('iphone-5', (done) => { cy.on('viewport:changed', (viewport) => { expect(viewport).to.deep.eq({ viewportWidth: 320, viewportHeight: 568 }) done() }) cy.viewport('iphone-5') }) it('can change the orientation to landspace', (done) => { cy.on('viewport:changed', (viewport) => { expect(viewport).to.deep.eq({ viewportWidth: 568, viewportHeight: 320 }) done() }) cy.viewport('iphone-5', 'landscape') }) it('can change the orientation to portrait', (done) => { cy.on('viewport:changed', (viewport) => { expect(viewport).to.deep.eq({ viewportWidth: 320, viewportHeight: 568 }) done() }) cy.viewport('iphone-5', 'portrait') }) it('samsung-s10', (done) => { cy.on('viewport:changed', (viewport) => { expect(viewport).to.deep.eq({ viewportWidth: 360, viewportHeight: 760 }) done() }) cy.viewport('samsung-s10') }) it('samsung-note9', (done) => { cy.on('viewport:changed', (viewport) => { expect(viewport).to.deep.eq({ viewportWidth: 414, viewportHeight: 846 }) done() }) cy.viewport('samsung-note9') }) it('macbook-16', (done) => { cy.on('viewport:changed', (viewport) => { expect(viewport).to.deep.eq({ viewportWidth: 1536, viewportHeight: 960 }) done() }) cy.viewport('macbook-16') }) }) context('errors', { defaultCommandTimeout: 50, }, () => { beforeEach(function () { this.logs = [] cy.on('log:added', (attrs, log) => { this.lastLog = log this.logs.push(log) }) return null }) it('throws when passed invalid preset', function (done) { cy.on('fail', (err) => { expect(this.logs.length).to.eq(1) expect(err.message).to.match(/^`cy.viewport\(\)` could not find a preset for: `foo`. Available presets are: /) expect(err.docsUrl).to.eq('https://on.cypress.io/viewport') done() }) cy.viewport('foo') }) it('throws when passed a string as height', function (done) { cy.on('fail', (err) => { expect(this.logs.length).to.eq(1) expect(err.message).to.eq('`cy.viewport()` can only accept a string preset or a `width` and `height` as numbers.') expect(err.docsUrl).to.eq('https://on.cypress.io/viewport') done() }) cy.viewport(800, '600') }) it('throws when passed negative numbers', function (done) { cy.on('fail', (err) => { expect(this.logs.length).to.eq(1) expect(err.message).to.eq('`cy.viewport()` `width` and `height` must be at least 0px.') expect(err.docsUrl).to.eq('https://on.cypress.io/viewport') done() }) cy.viewport(800, -600) }) it('does not throw when passed width equal to 0', () => { cy.viewport(0, 600) }) it('does not throw when passed width equal to 1000000', () => { cy.viewport(200, 1000000) }) it('throws when passed an empty string as width', function (done) { cy.on('fail', (err) => { expect(this.logs.length).to.eq(1) expect(err.message).to.eq('`cy.viewport()` cannot be passed an empty string.') expect(err.docsUrl).to.eq('https://on.cypress.io/viewport') done() }) cy.viewport('') }) it('throws when passed an invalid orientation on a preset', function (done) { cy.on('fail', (err) => { expect(this.logs.length).to.eq(1) expect(err.message).to.eq('`cy.viewport()` can only accept `landscape` or `portrait` as valid orientations. Your orientation was: `foobar`') expect(err.docsUrl).to.eq('https://on.cypress.io/viewport') done() }) cy.viewport('iphone-4', 'foobar') }) _.each([{}, [], NaN, Infinity, null, undefined], (val) => { it(`throws when passed the invalid: '${val}' as width`, function (done) { const logs = [] cy.on('log:added', (attrs, log) => { logs.push(log) }) cy.on('fail', (err) => { expect(this.logs.length).to.eq(1) expect(err.message).to.eq('`cy.viewport()` can only accept a string preset or a `width` and `height` as numbers.') expect(err.docsUrl).to.eq('https://on.cypress.io/viewport') done() }) cy.viewport(val) }) }) }) context('.log', () => { beforeEach(function () { this.logs = [] cy.on('log:added', (attrs, log) => { this.lastLog = log this.logs.push(log) }) return null }) it('logs viewport', () => { cy.viewport(800, 600).then(function () { const { lastLog } = this expect(lastLog.get('name')).to.eq('viewport') }) }) it('logs viewport with width, height', () => { cy.viewport(800, 600).then(function () { const { lastLog } = this expect(lastLog.get('message')).to.eq('800, 600') }) }) it('logs viewport with preset', () => { cy.viewport('ipad-2').then(function () { const { lastLog } = this expect(lastLog.get('message')).to.eq('ipad-2') }) }) it('sets state to success immediately', () => { cy.viewport(800, 600).then(function () { const { lastLog } = this expect(lastLog.get('state')).to.eq('passed') }) }) it('snapshots immediately', () => { cy.viewport(800, 600).then(function () { const { lastLog } = this expect(lastLog.get('snapshots').length).to.eq(1) expect(lastLog.get('snapshots')[0]).to.be.an('object') }) }) it('can turn off logging viewport command', () => { cy.viewport(800, 600, { log: false }).then(function () { expect(this.log).not.to.be.ok }) }) it('can turn off logging viewport when using preset', () => { cy.viewport('macbook-15', { log: false }).then(function () { expect(this.log).not.to.be.ok }) }) it('sets viewportWidth and viewportHeight directly', () => { cy.viewport(800, 600).then(function () { const { lastLog } = this expect(lastLog.get('viewportWidth')).to.eq(800) expect(lastLog.get('viewportHeight')).to.eq(600) }) }) it('.consoleProps with preset', () => { cy.viewport('ipad-mini').then(function () { expect(this.lastLog.invoke('consoleProps')).to.deep.eq({ Command: 'viewport', Preset: 'ipad-mini', Width: 768, Height: 1024, }) }) }) it('.consoleProps without preset', () => { cy.viewport(1024, 768).then(function () { expect(this.lastLog.invoke('consoleProps')).to.deep.eq({ Command: 'viewport', Width: 1024, Height: 768, }) }) }) }) }) })