在 Cypress 中,before 和 beforeEach 究竟是如何工作的?

Rhy*_*vil 7 javascript cypress

我想我遗漏了一些关于 before 和 beforeEach 函数在赛普拉斯中工作的方式。我有一个规范文件,它从 before 方法中的夹具加载数据。其中一些数据在 before 函数中使用,然后在 beforeEach 函数中以及在实际测试中再次使用。规范文件包含 2 个测试。第一个测试按预期执行。第二个失败,因为 beforeEach 表示夹具中的一个值是未定义的。

我的期望是,如果我从 before 方法中的夹具加载数据,它应该可用于规范文件中的所有测试。

执行“检查按钮栏的状态”时,测试 beforeEach 函数中的 window.console.log(this.user_data) 会按预期输出 user_data。

执行“提交表单”测试时,beforeEach 函数中的 window.console.log(this.user_data) 输出 undefined 并且测试停止。

我在这里缺少什么?

describe('Customer Profile', () => {

    before(function () {
        window.console.log('Enter the before function')
        // Load the fixture data. Its asynchronous so if we want to use it right here and now
        // we have to put the things that use inside a callback to be executed after the data
        // loaded. 
        cy.fixture('user').as('user_data').then(function (){
            window.console.log('Fixture has loaded the user data')
            cy.visit('/LaunchPad/login')
            // Fill out the login form
            cy.get('input[name="username"]').type(this.user_data.username)
            cy.get('input[name="password"]').type(this.user_data.password)
            cy.get('button[type="submit"]').click()
        })
    })

    beforeEach(function(){
        window.console.log('Enter the beforeEach function')
        window.console.log(this.user_data)
        // Preserve the cookies for all tests in this suite
        Cypress.Cookies.preserveOnce('SESSION')
        // Open the profile view
        cy.visit('/Manager/'+this.user_data.org+'/config/company-profile')
    })

    it('Check the state of the button bar', function(){
        window.console.log('Running test of button bar')
        cy.get('section.content-header > h1').contains('Company Profile Details')
        // Check the state of the action bar and its buttons
        cy.get('section.action-bar').get('label.btn.btn-sm.btn-primary').contains('Save')
            .should('have.attr', 'for', 'submit-form')
            .should('have.attr', 'tabindex', '0')

        cy.get('section.action-bar').get('#resetButton').contains('Reset')
            .should('have.attr', 'type', 'reset')
            .should('have.attr', 'value', 'Reset')
            .should('have.class', 'btn btn-sm btn-default')

        cy.get('section.action-bar').get('a.btn.btn-sm.btn-default').contains('Cancel')
            .should('have.attr', 'href', '/Manager/'+this.user_data.org+'/')

        cy.get('section.action-bar').get('a').contains('Delete').should('not.exist')

    })

    // This form has no required fields and no validation. So just pick a value or two
    // submit the form and verify the banner is correct
    it('Submit form', function(){
        window.console.log('Running the submit form test')
        cy.fixture('company_profile').as('company_profile')
        cy.get('#companyProfileDto.name').type(this.company_profile.name)
    })


})
Run Code Online (Sandbox Code Playgroud)

更新 在根据 Carlos Alfredo 的回应做了更多阅读之后,我想到了这个。1. 我还是要访问登录页面。我们使用 csrf 和 OATH 并且尝试获得工作示例只是花费了太多时间。2.我必须对会话cookie使用白名单,因为preserveOnce根本不起作用。

这是我现在拥有的文件。它访问登录页面一次并获取会话 cookie 设置。这两个测试按预期进行。

支持/index.js

before(function(){
    cy.login('bob', 'password')
    cy.fixture('user').as('user_data')
    cy.fixture('company_profile').as('company_profile')
})

beforeEach(function(){
    window.console.log('Enter the global beforeEach function')
    // Load the fixture data

})
Run Code Online (Sandbox Code Playgroud)

支持/commands.js

/*
    We visit the login form despite what the best practise recommendation is because
    we have OAUTH redirects and a CSRF token to deal with. Since the majority of the
    examples and working use cases provided dont deal with those scenarios this is 
    the best I can do at the moment. 
*/
Cypress.Commands.add('login', (username, password, options = {}) => {
    cy.visit('/LaunchPad/login')
    // Fill out the login form
    cy.get('input[name="username"]').type(username)
    cy.get('input[name="password"]').type(password)
    cy.get('button[type="submit"]').click()
})
/*
    We are white listing the cookie because Cypress.Cookies.preserveOnce('SESSION') 
    does not work. https://github.com/cypress-io/cypress/issues/2952

    Because we are forcing Cypress to not clear the cookies, you will have to close
    the test window after the suite is completed other wise the Vision360 apps will
    think your session is alive.
*/
Cypress.Cookies.defaults({
    whitelist: 'SESSION'
})
Run Code Online (Sandbox Code Playgroud)

集成/customer_profile/customer_profile_spec.js

describe('Customer Profile', () => {

    it('Check the state of the button bar', function(){
        window.console.log('Running test of button bar')

        cy.visit('/Manager/'+this.user_data.org+'/config/company-profile')

        cy.get('section.content-header > h1').contains('Company Profile Details')
        // Check the state of the action bar and its buttons
        cy.get('section.action-bar').get('label.btn.btn-sm.btn-primary').contains('Save')
            .should('have.attr', 'for', 'submit-form')
            .should('have.attr', 'tabindex', '0')

        cy.get('section.action-bar').get('#resetButton').contains('Reset')
            .should('have.attr', 'type', 'reset')
            .should('have.attr', 'value', 'Reset')
            .should('have.class', 'btn btn-sm btn-default')

        cy.get('section.action-bar').get('a.btn.btn-sm.btn-default').contains('Cancel')
            .should('have.attr', 'href', '/Manager/'+this.user_data.org+'/')

        cy.get('section.action-bar').get('a').contains('Delete').should('not.exist')

    })

    // This form has no required fields and no validation. So just pick a value or two
    // submit the form and verify the banner is correct
    it('Submit form', function(){
        window.console.log('Running the submit form test')
        cy.visit('/Manager/'+this.user_data.org+'/config/company-profile')

        // Fill and submit the form
        cy.get('input#companyProfileDto\\.name').clear().type(this.company_profile.name)
        cy.get('section.action-bar').get('label.btn.btn-sm.btn-primary').contains('Save').click()

        // Check the response
        cy.get('.callout-success').contains('Your changes are saved.')
        cy.get('input#companyProfileDto\\.name').should('have.value', this.company_profile.name)
    })

})
Run Code Online (Sandbox Code Playgroud)

JDT*_*One 10

我遇到了一个几乎和你之前一样的问题。

before() 在下一个代码块之前运行。

describe("Some test", function() {
    before(function() {
        //something ...
        cy.request('POST', loginUrl, loginInformation).its('body').as('currentUser')
    })

    // this.currentUser exists here
    it("Should foo", function() {
    })

    // this.currentUser doesn't exist here
    it("Should bar", function() {
    })
})
Run Code Online (Sandbox Code Playgroud)

我解决了将before()语句从描述范围移出的问题。

before(function() {
    //something ...
    cy.request('POST', loginUrl, loginInformation).its('body').as('currentUser')
})

describe("Some test", function() {     
    // this.currentUser exists here
    it("Should foo", function() {
    })

    // this.currentUser also exists here
    it("Should bar", function() {
    })
})
Run Code Online (Sandbox Code Playgroud)

我希望这可以帮助您解决您的问题。


小智 4

看起来 cypress 正在fixtures为每次测试清理你的数据。

来自赛普拉斯指南的回复:“悬空状态”

...事实上,Cypress在测试结束时并没有清理自己的内部状态。我们希望您在测试结束时处于悬空状态!像存根、间谍、甚至路由之类的东西在测试结束时都不会被删除。这意味着您的应用程序在运行赛普拉斯命令时或在测试结束后手动使用它时将表现相同。

该页面中没有任何明确的内容fixtures,但是看起来它正在发生并且fixtures也被清理了。这就是beforeEach()第一个测试中的工作(检查按钮栏的状态),因为它恰好在before(). 对于第二个测试,挂钩中设置的所有内容都before消失了,现在正在beforeEach()尝试获取从未定义的固定装置。

希望能帮助到你。

其他一些建议: