diff --git a/npm/cypress-schematic/src/e2e.spec.ts b/npm/cypress-schematic/src/e2e.spec.ts index e4d6042755b0..add1d333e549 100644 --- a/npm/cypress-schematic/src/e2e.spec.ts +++ b/npm/cypress-schematic/src/e2e.spec.ts @@ -27,7 +27,7 @@ const cypressSchematicPackagePath = path.join(__dirname, '..') const ANGULAR_PROJECTS: ProjectFixtureDir[] = ['angular-13', 'angular-14'] describe('ng add @cypress/schematic / only e2e', function () { - this.timeout(1000 * 60 * 5) + this.timeout(1000 * 60 * 4) for (const project of ANGULAR_PROJECTS) { it('should install e2e files by default', async () => { diff --git a/packages/driver/cypress/e2e/commands/agents.cy.js b/packages/driver/cypress/e2e/commands/agents.cy.js index 012bc1957836..73ef7c9ff851 100644 --- a/packages/driver/cypress/e2e/commands/agents.cy.js +++ b/packages/driver/cypress/e2e/commands/agents.cy.js @@ -323,6 +323,10 @@ describe('src/cy/commands/agents', () => { expect(cy.state('aliases').myStub).to.exist }) + it('stores the agent as the subject', function () { + expect(cy.state('aliases').myStub.subject).to.eq(this.stub) + }) + it('assigns subject to runnable ctx', function () { expect(this.myStub).to.eq(this.stub) }) @@ -400,6 +404,10 @@ describe('src/cy/commands/agents', () => { expect(cy.state('aliases')['my.stub']).to.exist }) + it('stores the agent as the subject', function () { + expect(cy.state('aliases')['my.stub'].subject).to.eq(this.stub) + }) + it('assigns subject to runnable ctx', function () { expect(this['my.stub']).to.eq(this.stub) }) diff --git a/packages/driver/cypress/e2e/commands/aliasing.cy.js b/packages/driver/cypress/e2e/commands/aliasing.cy.js index 18ff6704a99f..524c7c44259b 100644 --- a/packages/driver/cypress/e2e/commands/aliasing.cy.js +++ b/packages/driver/cypress/e2e/commands/aliasing.cy.js @@ -1,5 +1,5 @@ const { assertLogLength } = require('../../support/utils') -const { _ } = Cypress +const { _, $ } = Cypress describe('src/cy/commands/aliasing', () => { beforeEach(() => { @@ -7,6 +7,14 @@ describe('src/cy/commands/aliasing', () => { }) context('#as', () => { + it('is special utility command', () => { + cy.wrap('foo').as('f').then(() => { + const cmd = cy.queue.find({ name: 'as' }) + + expect(cmd.get('type')).to.eq('utility') + }) + }) + it('does not change the subject', () => { const body = cy.$$('body') @@ -26,13 +34,11 @@ describe('src/cy/commands/aliasing', () => { cy.get('@body') }) - it('stores the resulting subject chain as the alias', () => { - cy.get('body').as('b').then(() => { - const { subjectChain } = cy.state('aliases').b + it('stores the resulting subject as the alias', () => { + const $body = cy.$$('body') - expect(subjectChain.length).to.eql(2) - expect(subjectChain[0]).to.be.undefined - expect(subjectChain[1].commandName).to.eq('get') + cy.get('body').as('b').then(() => { + expect(cy.state('aliases').b.subject.get(0)).to.eq($body.get(0)) }) }) @@ -44,15 +50,6 @@ describe('src/cy/commands/aliasing', () => { }) }) - it('retries previous commands invoked inside custom commands', () => { - Cypress.Commands.add('get2', (selector) => cy.get(selector)) - - cy.get2('body').children('div').as('divs') - cy.visit('/fixtures/dom.html') - - cy.get('@divs') - }) - it('retries primitives and assertions', () => { const obj = {} @@ -90,13 +87,29 @@ describe('src/cy/commands/aliasing', () => { }) }) - it('retries previous commands invoked inside custom commands', () => { - Cypress.Commands.add('get2', (selector) => cy.get(selector)) + context('DOM subjects', () => { + it('assigns the remote jquery instance', () => { + const obj = {} + + const jquery = () => { + return obj + } + + cy.state('jQuery', jquery) + + cy.get('input:first').as('input').then(function () { + expect(this.input).to.eq(obj) + }) + }) + + it('retries previous commands invoked inside custom commands', () => { + Cypress.Commands.add('get2', (selector) => cy.get(selector)) - cy.get2('body').children('div').as('divs') - cy.visit('/fixtures/dom.html') + cy.get2('body').children('div').as('divs') + cy.visit('/fixtures/dom.html') - cy.get('@divs') + cy.get('@divs') + }) }) context('#assign', () => { @@ -315,8 +328,9 @@ describe('src/cy/commands/aliasing', () => { // sanity check without command overwrite cy.wrap('alias value').as('myAlias') .then(() => { - expect(cy.getAlias('@myAlias')).to.exist - expect(cy.getAlias('@myAlias').subjectChain).to.eql(['alias value']) + expect(cy.getAlias('@myAlias'), 'alias exists').to.exist + expect(cy.getAlias('@myAlias'), 'alias value') + .to.have.property('subject', 'alias value') }) .then(() => { // cy.get returns the alias @@ -335,9 +349,10 @@ describe('src/cy/commands/aliasing', () => { cy.wrap('alias value').as('myAlias') .then(() => { - expect(wrapCalled).to.be.true - expect(cy.getAlias('@myAlias')).to.exist - expect(cy.getAlias('@myAlias').subjectChain).to.eql(['alias value']) + expect(wrapCalled, 'overwrite was called').to.be.true + expect(cy.getAlias('@myAlias'), 'alias exists').to.exist + expect(cy.getAlias('@myAlias'), 'alias value') + .to.have.property('subject', 'alias value') }) .then(() => { // verify cy.get works in arrow function @@ -367,8 +382,9 @@ describe('src/cy/commands/aliasing', () => { .then(() => { expect(wrapCalled, 'overwrite was called').to.be.true expect(thenCalled, 'then was called').to.be.true - expect(cy.getAlias('@myAlias')).to.exist - expect(cy.getAlias('@myAlias').subjectChain).to.eql(['alias value']) + expect(cy.getAlias('@myAlias'), 'alias exists').to.exist + expect(cy.getAlias('@myAlias'), 'alias value') + .to.have.property('subject', 'alias value') }) .then(() => { // verify cy.get works in arrow function @@ -384,9 +400,9 @@ describe('src/cy/commands/aliasing', () => { // sanity test before the next one cy.wrap(1).as('myAlias') cy.wrap(2).then(function (subj) { - expect(subj).to.equal(2) - expect(this).to.not.be.undefined - expect(this.myAlias).to.eq(1) + expect(subj, 'subject').to.equal(2) + expect(this, 'this is defined').to.not.be.undefined + expect(this.myAlias, 'this has the alias as a property').to.eq(1) }) }) @@ -398,8 +414,8 @@ describe('src/cy/commands/aliasing', () => { cy.wrap(1).as('myAlias') cy.wrap(2).then(function (subj) { - expect(subj).to.equal(2) - expect(this).to.not.be.undefined + expect(subj, 'subject').to.equal(2) + expect(this, 'this is defined').to.not.be.undefined expect(this.myAlias).to.eq(1) }) }) @@ -412,61 +428,166 @@ describe('src/cy/commands/aliasing', () => { cy.wrap(1).as('myAlias') cy.wrap(2).then(function (subj) { - expect(subj).to.equal(2) - expect(this).to.not.be.undefined + expect(subj, 'subject').to.equal(2) + expect(this, 'this is defined').to.not.be.undefined expect(this.myAlias).to.eq(1) }) }) }) }) - context('#replaying subjects', () => { - it('returns if subject is still in the document', () => { - cy.get('#list').as('list').then((firstList) => { - cy.get('@list').then((secondList) => { - expect(firstList).to.eql(secondList) + context('#replayCommandsFrom', () => { + describe('subject in document', () => { + it('returns if subject is still in the document', () => { + cy.get('#list').as('list').then(() => { + const currentLength = cy.queue.length + + cy.get('@list').then(() => { + // should only add the .get() and the .then() + expect(cy.queue.length).to.eq(currentLength + 2) + }) }) }) }) - it('requeries when reading alias', () => { - cy - .get('#list li') - .as('items').then((firstItems) => { - cy.$$('#list').append('
  • 123456789
  • ') + describe('subject not in document', () => { + it('inserts into the queue', () => { + const existingNames = cy.queue.names() - cy.get('@items').then((secondItems) => { - expect(firstItems).to.have.length(3) - expect(secondItems).to.have.length(4) + cy + .get('#list li').eq(0).as('firstLi').then(($li) => { + return $li.remove() + }) + .get('@firstLi').then(() => { + expect(cy.queue.names()).to.deep.eq( + existingNames.concat( + ['get', 'eq', 'as', 'then', 'get', 'get', 'eq', 'then'], + ), + ) }) }) - }) - it('requeries when subject is not in the DOM', () => { - cy - .get('#list li') - .as('items').then((firstItems) => { - firstItems.remove() - setTimeout(() => { - cy.$$('#list').append('
  • 123456789
  • ') - }, 50) + it('replays from last root to current', () => { + const first = cy.$$('#list li').eq(0) + const second = cy.$$('#list li').eq(1) + + cy + .get('#list li').eq(0).as('firstLi').then(($li) => { + expect($li.get(0)).to.eq(first.get(0)) - cy.get('@items').then((secondItems) => { - expect(secondItems).to.have.length(1) + return $li.remove() + }) + .get('@firstLi').then(($li) => { + expect($li.get(0)).to.eq(second.get(0)) }) }) - }) - it('only retries up to last command', () => { - cy - .get('#list li') - .then((items) => items.length) - .as('itemCount') - .then(() => cy.$$('#list li').remove()) - - // Even though the list items have been removed from the DOM, 'then' can't be retried - // so we just have the primitive value "3" as our subject. - cy.get('@itemCount').should('eq', 3) + it('replays up until first root command', () => { + const existingNames = cy.queue.names() + + cy + .get('body').noop({}) + .get('#list li').eq(0).as('firstLi').then(($li) => { + return $li.remove() + }) + .get('@firstLi').then(() => { + expect(cy.queue.names()).to.deep.eq( + existingNames.concat( + ['get', 'noop', 'get', 'eq', 'as', 'then', 'get', 'get', 'eq', 'then'], + ), + ) + }) + }) + + it('resets the chainerId allow subjects to be carried on', () => { + cy.get('#dom').find('#button').as('button').then(($button) => { + $button.remove() + + cy.$$('#dom').append($('