Cypress中调用cy.函数仅能推送数组最后一项的问题求助
问题:Cypress中数组无法正确存储多网站产品数据,仅保留最后一项
学习Cypress时,尝试从不同网站抓取产品数据存入数组并排序,但调用cy命令后,数组只能保留最后一项数据,beforeEach()和afterEach()运行正常。期望实现所有网站的产品数据都能正确推入数组并输出。
初始可正常运行的代码
describe('Compare iPhone 15 Pro between eBay and Apple Store', () => { let productDetails = []; beforeEach(() => { // Load the existing productDetails array from localStorage if it exists const storedProductDetails = localStorage.getItem('productDetails'); if (storedProductDetails) { productDetails = JSON.parse(storedProductDetails); } }); afterEach(() => { // Store the productDetails array back into localStorage localStorage.setItem('productDetails', JSON.stringify(productDetails)); }); it('Visit eBay and gets the product details', () => { // Visit eBay and get product details // ... productDetails.push({ website: 'eBay', product: 'iPhone 15 Pro 256GB', price: itemPrice, link: linkValue }); }); it('Visit Apple store and gets the product details', () => { // Visit Apple store and get product details // ... productDetails.push({ website: 'Apple Store', product: 'iPhone 15 Pro 256GB', price: itemPrice, link: linkValue }); }); it('Print the product details array', () => { // Log the product details array for (let i = 0; i < productDetails.length; i++) { cy.log('Product Details: ' + JSON.stringify(productDetails[i])); } }); });
添加cy函数后仅保留最后一项的代码
describe('Compare iPhone 15 Pro between eBay and Apple Store', () => { let productDetails = []; beforeEach(() => { // Load the existing productDetails array from localStorage if it exists const storedProductDetails = localStorage.getItem('productDetails'); if (storedProductDetails) { productDetails = JSON.parse(storedProductDetails); } }); afterEach(() => { // Store the productDetails array back into localStorage localStorage.setItem('productDetails', JSON.stringify(productDetails)); }); it('Visit eBay and gets the product details', () => { // Visit eBay and get product details // ... cy.visit('https://www.ebay.com.my/'); // Search for iPhone 15 Pro 256GB cy.get('input.gh-tb[name="_nkw"]').type('iphone 15 pro 256gb new'); // class & attribute cy.get('input#gh-btn').click(); cy.get('.srp-results.srp-list.clearfix').within(() => { cy.get('li').first().should('be.visible'); }); cy.get('li#item405343ae00 span.s-item__price span.ITALIC').invoke('text').then((price) => { const itemPrice = price; cy.log('Price: ', itemPrice); cy.url().then(url => { cy.log('Current URL:', url); const linkValue = url; productDetails.push({ website: 'eBay', product: 'iPhone 15 Pro 256GB', price: itemPrice, link: linkValue }); localStorage.setItem('productDetails', JSON.stringify(productDetails)); cy.log('Product Details eBay: ', productDetails); }); }); //productDetails.push({ website: 'eBay', product: 'iPhone 15 Pro 256GB', price: 'itemPrice', link: 'linkValue' }); }); it('Visit Apple store and gets the product details', () => { // Visit Apple store and get product details // ... cy.visit('https://www.apple.com/my/'); cy.get('#globalnav-menubutton-link-search').click(); cy.get('.globalnav-searchfield-input').type('iphone 15 pro 256gb new').type('{enter}'); cy.get('[data-analytics-title="iPhone 15 Pro and iPhone 15 Pro Max - Apple (MY)"]').click(); cy.title().should('eq','iPhone 15 Pro and iPhone 15 Pro Max - Apple (MY)'); cy.contains(/Buy/i); cy.get('.welcome__lockup-cta.show').click(); cy.contains(/Buy iPhone 15 Pro/i); cy.get('.rc-dimension-selector-group.form-selector-group .rc-dimension-selector-row.form-selector').first().click(); cy.get('.colornav-items').within(() => { cy.get('li').first().click(); }); cy.get('.form-selector-title:contains("256")').click(); cy.contains(/iPhone 15 Pro/i); cy.wait(2000); cy.get('.rc-prices-fullprice[data-autom="full-price"]').first().invoke('text').then((price) => { const itemPrice = price; cy.log('Price: ', itemPrice); cy.url().then(url => { cy.log('Current URL:', url); const linkValue = url; productDetails.push({website: 'Apple Store', product: 'iPhone 15 Pro 256GB', price: itemPrice, link: linkValue}); localStorage.setItem('productDetails', JSON.stringify(productDetails)); cy.log('Product Details: ', productDetails); }); }); //productDetails.push({ website: 'Apple Store', product: 'iPhone 15 Pro 256GB', price: 'itemPrice', link: 'linkValue' }); }); it('Print the product details array', () => { // Log the product details array for (let i = 0; i < productDetails.length; i++) { cy.log('Product Details: ' + JSON.stringify(productDetails[i])); } }); });
问题原因
- 环境隔离:Cypress测试代码运行在Node.js环境,直接调用
localStorage访问的是Node环境的存储,而非测试页面的浏览器localStorage,两者完全独立,导致数据无法正确共享。 - 异步时序:cy命令是异步执行的,beforeEach/afterEach是同步执行的,afterEach执行时,cy回调里的数组push操作还未完成,存储的仍是初始空数组。
解决方案
改用Cypress环境变量跨用例共享数据,并通过cy.window()访问浏览器localStorage,确保数据正确累加:
describe('Compare iPhone 15 Pro between eBay and Apple Store', () => { beforeEach(() => { // 从浏览器localStorage加载数据到Cypress环境变量 cy.window().then(win => { const storedDetails = win.localStorage.getItem('productDetails'); Cypress.env('productDetails', storedDetails ? JSON.parse(storedDetails) : []); }); }); afterEach(() => { // 将环境变量中的数据存入浏览器localStorage cy.window().then(win => { const details = Cypress.env('productDetails') || []; win.localStorage.setItem('productDetails', JSON.stringify(details)); }); }); it('Visit eBay and gets the product details', () => { cy.visit('https://www.ebay.com.my/'); cy.get('input.gh-tb[name="_nkw"]').type('iphone 15 pro 256gb new'); cy.get('input#gh-btn').click(); cy.get('.srp-results.srp-list.clearfix').within(() => { cy.get('li').first().should('be.visible'); }); cy.get('li#item405343ae00 span.s-item__price span.ITALIC').invoke('text').then(price => { cy.url().then(url => { // 获取当前数组并添加新数据 const currentDetails = Cypress.env('productDetails'); currentDetails.push({ website: 'eBay', product: 'iPhone 15 Pro 256GB', price: price, link: url }); Cypress.env('productDetails', currentDetails); cy.log('Product Details eBay: ', currentDetails); }); }); }); it('Visit Apple store and gets the product details', () => { cy.visit('https://www.apple.com/my/'); cy.get('#globalnav-menubutton-link-search').click(); cy.get('.globalnav-searchfield-input').type('iphone 15 pro 256gb new').type('{enter}'); cy.get('[data-analytics-title="iPhone 15 Pro and iPhone 15 Pro Max - Apple (MY)"]').click(); cy.title().should('eq','iPhone 15 Pro and iPhone 15 Pro Max - Apple (MY)'); cy.contains(/Buy/i); cy.get('.welcome__lockup-cta.show').click(); cy.contains(/Buy iPhone 15 Pro/i); cy.get('.rc-dimension-selector-group.form-selector-group .rc-dimension-selector-row.form-selector').first().click(); cy.get('.colornav-items').within(() => { cy.get('li').first().click(); }); cy.get('.form-selector-title:contains("256")').click(); cy.contains(/iPhone 15 Pro/i); cy.wait(2000); cy.get('.rc-prices-fullprice[data-autom="full-price"]').first().invoke('text').then(price => { cy.url().then(url => { const currentDetails = Cypress.env('productDetails'); currentDetails.push({ website: 'Apple Store', product: 'iPhone 15 Pro 256GB', price: price, link: url }); Cypress.env('productDetails', currentDetails); cy.log('Product Details Apple: ', currentDetails); }); }); }); it('Print and sort the product details array', () => { const details = Cypress.env('productDetails') || []; // 输出原始数据 details.forEach(item => { cy.log('Product Details: ' + JSON.stringify(item)); }); // 按价格排序(处理价格字符串,去除非数字字符后转数字) const sortedDetails = [...details].sort((a, b) => { const priceA = parseFloat(a.price.replace(/[^0-9.]/g, '')); const priceB = parseFloat(b.price.replace(/[^0-9.]/g, '')); return priceA - priceB; }); cy.log('Sorted Product Details (ascending price): ', sortedDetails); }); });
修改说明
- 使用
Cypress.env()存储数组,实现跨测试用例的数据共享,避免全局变量的异步时序问题。 - 通过
cy.window()访问浏览器的localStorage,确保和测试页面的存储环境一致。 - 在每个异步回调中,先获取当前数组再添加新数据,保证数据正确累加。
- 添加了价格排序逻辑,满足需求。
内容的提问来源于stack exchange,提问作者sm.chan
相关产品推荐
相关产品推荐

