我有以下流程:
1)在一页上,我得到一个字段的值:
var myID;
cy.get('#MYID').
then(($txt) => {
myID= $txt.text();
})
.should('not.equal', null);
2)然后,我导航到新页面并尝试检查此新页面是否包含此ID:
cy.get('#myTable').find('td').contains(myID);
它表示未定义myID。我知道第一个功能是异步的,请阅读说明它可以使用别名的文档。别名的问题在于,它必须位于beforeEach()函数中,不要长篇大论,在这个测试案例中我无法使用。我尝试使用async / await,但由于它仍未定义,因此对我似乎不起作用。
答案 0 :(得分:1)
这里的基本问题是Cypress命令与创建它们的测试代码异步运行。如果您将控制台日志放入代码中,就会看到此信息,
var myID;
cy.get('#MYID')
.then(($txt) => {
myID= $txt.text();
console.log('1', myID);
})
.should('not.equal', null);
console.log('2', myID);
这将打印出来
2 undefined
1 myText
您可以使用别名来克服此问题,并在命令链中传递一个值。
请参见此section of the docs,该示例显示了在“请勿使用此”示例中使用的类似代码。
在测试之间清除 BUT 别名,因此您应该设置beforeEach()
以获得每个测试所需ID的新副本。
获取文本值的方式还有另一个问题。
在没有return语句的情况下,.then()
命令会将接收到的任何主题传递给下一个命令。参见then- Yields
另外,回调函数中最后一个赛普拉斯命令的结果将作为新主题产生,并在没有返回值的情况下流入下一个命令 。< / p>
因此.should('not.equal', null)
正在测试元素不为null,而不是文本也不为空。
更好的方法是转到.invoke('text')
,它等效于$txt.text()
并将文本值产生到.should()
。
.should('not.equal', null)
也不会测试内容是否存在,因为空元素会从element.text()
返回空字符串。请改用.should('not.equal', '')
。
通过别名保存
describe('grabbing ID for use in multiple tests', () => {
beforeEach(() => {
cy.visit('my-page-1.html')
cy.get('#MYID')
.invoke('text')
.as('mySavedID')
})
it('ID should not be null', () => {
cy.get('@mySavedID')
.should('not.equal', '')
})
it('ID should be found in table', () => {
cy.visit('app/navigate-to-new-page-2.html');
cy.get('@mySavedID').then(myID => {
cy.get('#myTable').find('td').contains(myID);
})
})
})
通过排队设置变量进行保存
如果访问第1页非常耗时,则别名模式可能并不理想。
在这种情况下,您可以通过自定义命令保存变量。区别在于您在.then()
中拥有的代码被移到了排队的命令中,因此不会发生异步问题。
describe('grabbing ID for use in multiple tests', () => {
let savedVariable;
Cypress.Commands.add("saveVariable", {prevSubject: true}, (value) => {
savedVariable = value;
});
it('id should not be null', () => {
cy.visit('my-page-1')
cy.get('#someId')
.invoke('text')
.should('not.equal', '')
.saveVariable()
// OR test the variable separately like this
cy.wrap(savedVariable)
.should('not.equal', '')
})
it('id should be found in table', () => {
cy.visit('my-page-2');
cy.get('#myTable').find('td').contains(savedVariable);
})
})
注意
如果两个页面位于同一域中,例如SPA的两个页面,则以上内容有效。否则,测试运行程序会在遇到新域时重置自身,并且所有javascript变量都将丢失。
答案 1 :(得分:1)
在插件级别保存数据并通过任务访问它。调用 cy.visit
时会重新加载其他级别。将 data
和任务添加到 plugins/index.js
:
// plugins/index.js
/// <reference types="cypress" />
module.exports = (on, config) => {
// data will be stored here
const data = {};
// configuring tasks
on('task', {
setValue: (params) => {
const { key, value } = params;
data[key] = value;
return value;
},
getValue: (params) => {
const { key } = params;
return data[key] || null;
}
})
}
并在场景中使用:
// my.spec.js
/// <reference types="cypress" />
context('keeps data safe when changing pages', () => {
it('visits first page and saves data', () => {
return cy.visit('https://google.com').then(() => {
// saving data
return cy.task('setValue', { key: 'visited', value: 'google' });
})
});
it('visits another page and checks that data is available', () => {
return cy.visit('https://example.com').then(() => {
// getting data
return cy.task('getValue', { key: 'visited' });
}).then((value) => {
expect(value).to.equal('google');
});
})
});
答案 2 :(得分:0)
不确定这是否是个好主意,但您可以将数据保存在 Cypress 全局对象上。
context('Pass data via the Cypress object', () => {
before(() => {
Cypress._savedData = {}
})
it('visits first page and saves data', () => {
cy.visit('https://google.com');
cy.get('#MYID')
.should('not.equal', null)
.then($el => Cypress._savedData[myID] = $el.text() )
});
it('visits another page and checks that data is available', () => {
cy.visit('https://example.com');
cy.get('#myTable').find('td').contains(Cypress._savedData[myID]);
})
});