From 46e2a7fb17d9aa11edc8b447d673ddc3b8f61f5e Mon Sep 17 00:00:00 2001 From: Zach Panzarino Date: Tue, 28 Jul 2020 21:13:45 -0400 Subject: [PATCH 1/5] fix: it.skip no longer causes hooks to be assigned to the wrong test --- packages/driver/src/cypress/runner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/driver/src/cypress/runner.js b/packages/driver/src/cypress/runner.js index fb3abd283f1c..c77a4e8b872b 100644 --- a/packages/driver/src/cypress/runner.js +++ b/packages/driver/src/cypress/runner.js @@ -622,7 +622,7 @@ const _runnerListeners = (_runner, Cypress, _emissions, getTestById, getTest, se // hooks do not have their own id, their // commands need to grouped with the test // and we can only associate them by this id - const test = getTest() || getTestFromHookOrFindTest(hook) + const test = getTestFromHookOrFindTest(hook) if (!test) { // we couldn't find a test to run with this hook From 054a2bb0f774abdb7139dae842bbd9c04a8e1a7e Mon Sep 17 00:00:00 2001 From: Zach Panzarino Date: Wed, 29 Jul 2020 12:14:10 -0400 Subject: [PATCH 2/5] Update hook test assignment on fail too --- packages/driver/src/cypress/runner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/driver/src/cypress/runner.js b/packages/driver/src/cypress/runner.js index c77a4e8b872b..6f35823babeb 100644 --- a/packages/driver/src/cypress/runner.js +++ b/packages/driver/src/cypress/runner.js @@ -545,7 +545,7 @@ const hookFailed = (hook, err, hookName, getTest, getTestFromHookOrFindTest) => // NOTE: sometimes mocha will fail a hook without having emitted on('hook') // event, so this hook might not have currentTest set correctly // in which case we need to lookup the test - const test = getTest() || getTestFromHookOrFindTest(hook) + const test = getTestFromHookOrFindTest(hook) test.err = err test.state = 'failed' From cde6cfef3eebf68e08428a566b77f11e0fde248b Mon Sep 17 00:00:00 2001 From: Zach Panzarino Date: Wed, 29 Jul 2020 12:59:03 -0400 Subject: [PATCH 3/5] Add more isolated runner test specs --- .../{hook_spec.js => hooks/basic_spec.js} | 0 .../cypress/fixtures/hooks/only_spec.js | 31 ++++ .../cypress/fixtures/hooks/skip_spec.js | 15 ++ .../integration/reporter.hooks.spec.js | 148 ++++++++++++------ 4 files changed, 146 insertions(+), 48 deletions(-) rename packages/runner/cypress/fixtures/{hook_spec.js => hooks/basic_spec.js} (100%) create mode 100644 packages/runner/cypress/fixtures/hooks/only_spec.js create mode 100644 packages/runner/cypress/fixtures/hooks/skip_spec.js diff --git a/packages/runner/cypress/fixtures/hook_spec.js b/packages/runner/cypress/fixtures/hooks/basic_spec.js similarity index 100% rename from packages/runner/cypress/fixtures/hook_spec.js rename to packages/runner/cypress/fixtures/hooks/basic_spec.js diff --git a/packages/runner/cypress/fixtures/hooks/only_spec.js b/packages/runner/cypress/fixtures/hooks/only_spec.js new file mode 100644 index 000000000000..8bf00531c9c9 --- /dev/null +++ b/packages/runner/cypress/fixtures/hooks/only_spec.js @@ -0,0 +1,31 @@ +describe('test wrapper', () => { + it('test 1', () => { + cy.log('testBody 1') + }) + + describe('nested suite 1', () => { + beforeEach(() => { + cy.log('beforeEachHook 1') + }) + + it.only('test 2', () => { + cy.log('testBody 2') + }) + }) + + describe('nested suite 2', () => { + beforeEach(() => { + cy.log('beforeEachHook 2') + }) + + it('test 3', () => { + cy.log('testBody 3') + }) + }) + + describe('nested suite 3', () => { + it.only('test 4', () => { + cy.log('testBody 4') + }) + }) +}) diff --git a/packages/runner/cypress/fixtures/hooks/skip_spec.js b/packages/runner/cypress/fixtures/hooks/skip_spec.js new file mode 100644 index 000000000000..55fac958f4a6 --- /dev/null +++ b/packages/runner/cypress/fixtures/hooks/skip_spec.js @@ -0,0 +1,15 @@ +describe('outer suite', () => { + it.skip('test 1', () => { + cy.log('testBody 1') + }) + + describe('inner suite', () => { + before(() => { + cy.log('beforeHook 1') + }) + + it('test 2', () => { + cy.log('testBody 2') + }) + }) +}) diff --git a/packages/runner/cypress/integration/reporter.hooks.spec.js b/packages/runner/cypress/integration/reporter.hooks.spec.js index b5bf213b7c90..9b58c767b7e1 100644 --- a/packages/runner/cypress/integration/reporter.hooks.spec.js +++ b/packages/runner/cypress/integration/reporter.hooks.spec.js @@ -4,67 +4,119 @@ const { createCypress } = helpers const { runIsolatedCypress } = createCypress() describe('hooks', function () { - beforeEach(function () { - this.editor = {} - - return runIsolatedCypress(`cypress/fixtures/hook_spec.js`, { - onBeforeRun: ({ win }) => { - this.win = win - - win.runnerWs.emit.withArgs('get:user:editor') - .yields({ - preferredOpener: this.editor, - }) - }, + describe('displays hooks', function () { + beforeEach(function () { + return runIsolatedCypress(`cypress/fixtures/hooks/basic_spec.js`) }) - }) - it('displays commands under correct hook', function () { - cy.contains('tests 1').click() + it('displays commands under correct hook', function () { + cy.contains('tests 1').click() - cy.contains('before all').closest('.collapsible').should('contain', 'beforeHook 1') - cy.contains('before each').closest('.collapsible').should('contain', 'beforeEachHook 1') - cy.contains('test body').closest('.collapsible').should('contain', 'testBody 1') - cy.contains('after each').closest('.collapsible').should('contain', 'afterEachHook 1') - }) + cy.contains('before all').closest('.collapsible').should('contain', 'beforeHook 1') + cy.contains('before each').closest('.collapsible').should('contain', 'beforeEachHook 1') + cy.contains('test body').closest('.collapsible').should('contain', 'testBody 1') + cy.contains('after each').closest('.collapsible').should('contain', 'afterEachHook 1') + }) - it('displays hooks without number when only one of type', function () { - cy.contains('tests 1').click() + it('displays hooks without number when only one of type', function () { + cy.contains('tests 1').click() - cy.contains('before all').should('not.contain', '(1)') - cy.contains('before each').should('not.contain', '(1)') - cy.contains('after each').should('not.contain', '(1)') + cy.contains('before all').should('not.contain', '(1)') + cy.contains('before each').should('not.contain', '(1)') + cy.contains('after each').should('not.contain', '(1)') + }) + + it('displays hooks separately with number when more than one of type', function () { + cy.contains('tests 2').click() + + cy.contains('before all (1)').closest('.collapsible').should('contain', 'beforeHook 2') + cy.contains('before all (2)').closest('.collapsible').should('contain', 'beforeHook 3') + cy.contains('before each (1)').closest('.collapsible').should('contain', 'beforeEachHook 1') + cy.contains('before each (2)').closest('.collapsible').should('contain', 'beforeEachHook 2') + cy.contains('test body').closest('.collapsible').should('contain', 'testBody 2') + cy.contains('after each (1)').closest('.collapsible').should('contain', 'afterEachHook 2') + cy.contains('after each (2)').closest('.collapsible').should('contain', 'afterEachHook 1') + cy.contains('after all (1)').closest('.collapsible').should('contain', 'afterHook 2') + cy.contains('after all (2)').closest('.collapsible').should('contain', 'afterHook 1') + }) }) - it('displays hooks separately with number when more than one of type', function () { - cy.contains('tests 2').click() - - cy.contains('before all (1)').closest('.collapsible').should('contain', 'beforeHook 2') - cy.contains('before all (2)').closest('.collapsible').should('contain', 'beforeHook 3') - cy.contains('before each (1)').closest('.collapsible').should('contain', 'beforeEachHook 1') - cy.contains('before each (2)').closest('.collapsible').should('contain', 'beforeEachHook 2') - cy.contains('test body').closest('.collapsible').should('contain', 'testBody 2') - cy.contains('after each (1)').closest('.collapsible').should('contain', 'afterEachHook 2') - cy.contains('after each (2)').closest('.collapsible').should('contain', 'afterEachHook 1') - cy.contains('after all (1)').closest('.collapsible').should('contain', 'afterHook 2') - cy.contains('after all (2)').closest('.collapsible').should('contain', 'afterHook 1') + describe('open in IDE', function () { + beforeEach(function () { + this.editor = {} + + return runIsolatedCypress(`cypress/fixtures/hooks/basic_spec.js`, { + onBeforeRun: ({ win }) => { + this.win = win + + win.runnerWs.emit.withArgs('get:user:editor') + .yields({ + preferredOpener: this.editor, + }) + }, + }) + }) + + it('creates open in IDE button', function () { + cy.contains('tests 1').click() + + cy.get('.hook-open-in-ide').should('have.length', 4) + }) + + it('properly opens file in IDE at hook', function () { + cy.contains('tests 1').click() + + cy.contains('Open in IDE').invoke('show').click().then(function () { + expect(this.win.runnerWs.emit.withArgs('open:file').lastCall.args[1].file).to.include('basic_spec.js') + // chrome sets the column to right before "before(" + // while firefox sets it right after "before(" + expect(this.win.runnerWs.emit.withArgs('open:file').lastCall.args[1].column).to.be.eq(Cypress.browser.family === 'firefox' ? 10 : 3) + expect(this.win.runnerWs.emit.withArgs('open:file').lastCall.args[1].line).to.be.eq(2) + }) + }) }) - it('creates open in IDE button', function () { - cy.contains('tests 1').click() + describe('skipped tests', function () { + beforeEach(function () { + return runIsolatedCypress(`cypress/fixtures/hooks/skip_spec.js`) + }) + + it('does not display commands from skipped tests', function () { + cy.contains('test 1').click() + + cy.contains('test 1').parents('.collapsible').first().should('not.contain', 'testBody 1') + }) + + // https://github.com/cypress-io/cypress/issues/8086 + it('displays before hook when following it.skip', function () { + cy.contains('test 2').click() - cy.get('.hook-open-in-ide').should('have.length', 4) + cy.contains('test 2').parents('.collapsible').first().should('contain', 'before all') + }) }) - it('properly opens file in IDE at hook', function () { - cy.contains('tests 1').click() + describe('only tests', function () { + beforeEach(function () { + return runIsolatedCypress(`cypress/fixtures/hooks/only_spec.js`) + }) + + it('only displays tests with .only', function () { + cy.contains('test wrapper').parents('.collapsible').first().should(($suite) => { + expect($suite).not.to.contain('test 1') + expect($suite).to.contain('nested suite 1') + expect($suite).to.contain('test 2') + expect($suite).not.to.contain('nested suite 2') + expect($suite).not.to.contain('test 3') + expect($suite).to.contain('nested suite 3') + expect($suite).to.contain('test 4') + }) + + cy.contains('test 2').click() - cy.contains('Open in IDE').invoke('show').click().then(function () { - expect(this.win.runnerWs.emit.withArgs('open:file').lastCall.args[1].file).to.include('hook_spec.js') - // chrome sets the column to right before "before(" - // while firefox sets it right after "before(" - expect(this.win.runnerWs.emit.withArgs('open:file').lastCall.args[1].column).to.be.eq(Cypress.browser.family === 'firefox' ? 10 : 3) - expect(this.win.runnerWs.emit.withArgs('open:file').lastCall.args[1].line).to.be.eq(2) + cy.contains('test 2').parents('.collapsible').first().should(($test) => { + expect($test).to.contain('before each') + expect($test).to.contain('test body') + }) }) }) }) From 446cc39b1117043baa1c1949a504ae594f3f4d52 Mon Sep 17 00:00:00 2001 From: Zach Panzarino Date: Thu, 30 Jul 2020 15:58:51 -0400 Subject: [PATCH 4/5] Clean up getTest variables --- packages/driver/src/cypress/runner.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/driver/src/cypress/runner.js b/packages/driver/src/cypress/runner.js index 6f35823babeb..a79fae2806ac 100644 --- a/packages/driver/src/cypress/runner.js +++ b/packages/driver/src/cypress/runner.js @@ -541,7 +541,7 @@ const normalize = (runnable, tests, initialTests, onRunnable, onLogsById, getTes return normalizedRunnable } -const hookFailed = (hook, err, hookName, getTest, getTestFromHookOrFindTest) => { +const hookFailed = (hook, err, hookName, getTestFromHookOrFindTest) => { // NOTE: sometimes mocha will fail a hook without having emitted on('hook') // event, so this hook might not have currentTest set correctly // in which case we need to lookup the test @@ -571,7 +571,7 @@ function getTestFromRunnable (runnable) { } } -const _runnerListeners = (_runner, Cypress, _emissions, getTestById, getTest, setTest, getHookId, getTestFromHookOrFindTest) => { +const _runnerListeners = (_runner, Cypress, _emissions, getTestById, setTest, getHookId, getTestFromHookOrFindTest) => { _runner.on('start', () => { return Cypress.action('runner:start', { start: new Date(), @@ -751,7 +751,7 @@ const _runnerListeners = (_runner, Cypress, _emissions, getTestById, getTest, se // if a hook fails (such as a before) then the test will never // get run and we'll need to make sure we set the test so that // the TEST_AFTER_RUN_EVENT fires correctly - return hookFailed(runnable, runnable.err, hookName, getTest, getTestFromHookOrFindTest) + return hookFailed(runnable, runnable.err, hookName, getTestFromHookOrFindTest) } }) } @@ -928,7 +928,7 @@ const create = (specWindow, mocha, Cypress, cy) => { _startTime = moment().toJSON() } - _runnerListeners(_runner, Cypress, _emissions, getTestById, getTest, setTest, getHookId, getTestFromHookOrFindTest) + _runnerListeners(_runner, Cypress, _emissions, getTestById, setTest, getHookId, getTestFromHookOrFindTest) return _runner.run((failures) => { // if we happen to make it all the way through From 34d1c2da414d3065e18d0df8b0806bd784abe0bc Mon Sep 17 00:00:00 2001 From: Ben Kucera <14625260+Bkucera@users.noreply.github.com> Date: Mon, 3 Aug 2020 12:52:29 -0400 Subject: [PATCH 5/5] only remove neccessary call to getTest() --- packages/driver/src/cypress/runner.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/driver/src/cypress/runner.js b/packages/driver/src/cypress/runner.js index a79fae2806ac..c77a4e8b872b 100644 --- a/packages/driver/src/cypress/runner.js +++ b/packages/driver/src/cypress/runner.js @@ -541,11 +541,11 @@ const normalize = (runnable, tests, initialTests, onRunnable, onLogsById, getTes return normalizedRunnable } -const hookFailed = (hook, err, hookName, getTestFromHookOrFindTest) => { +const hookFailed = (hook, err, hookName, getTest, getTestFromHookOrFindTest) => { // NOTE: sometimes mocha will fail a hook without having emitted on('hook') // event, so this hook might not have currentTest set correctly // in which case we need to lookup the test - const test = getTestFromHookOrFindTest(hook) + const test = getTest() || getTestFromHookOrFindTest(hook) test.err = err test.state = 'failed' @@ -571,7 +571,7 @@ function getTestFromRunnable (runnable) { } } -const _runnerListeners = (_runner, Cypress, _emissions, getTestById, setTest, getHookId, getTestFromHookOrFindTest) => { +const _runnerListeners = (_runner, Cypress, _emissions, getTestById, getTest, setTest, getHookId, getTestFromHookOrFindTest) => { _runner.on('start', () => { return Cypress.action('runner:start', { start: new Date(), @@ -751,7 +751,7 @@ const _runnerListeners = (_runner, Cypress, _emissions, getTestById, setTest, ge // if a hook fails (such as a before) then the test will never // get run and we'll need to make sure we set the test so that // the TEST_AFTER_RUN_EVENT fires correctly - return hookFailed(runnable, runnable.err, hookName, getTestFromHookOrFindTest) + return hookFailed(runnable, runnable.err, hookName, getTest, getTestFromHookOrFindTest) } }) } @@ -928,7 +928,7 @@ const create = (specWindow, mocha, Cypress, cy) => { _startTime = moment().toJSON() } - _runnerListeners(_runner, Cypress, _emissions, getTestById, setTest, getHookId, getTestFromHookOrFindTest) + _runnerListeners(_runner, Cypress, _emissions, getTestById, getTest, setTest, getHookId, getTestFromHookOrFindTest) return _runner.run((failures) => { // if we happen to make it all the way through