使用Cypress测试Outlook集成遇新窗口问题的解决方法
Cypress 原生运行在单浏览器上下文沙箱中,默认无法直接捕获target="_blank"或JSwindow.open()触发的新窗口、新标签页跳转。Outlook 集成的登录流程(尤其是微软MSAL库默认的弹窗登录模式)会触发跨域新窗跳转,此时原测试页上下文丢失,流程会静默中断,不会抛出常规的断言或执行错误。
拦截新窗口跳转,强制在当前标签页加载
在测试用例的beforeEach钩子中全局拦截新窗口打开行为,强制所有跳转都在当前Cypress控制的页面上下文中执行,同时移除页面上所有会触发新窗的元素属性:beforeEach(() => { // 拦截JS window.open调用 cy.on('window:before:load', (win) => { cy.stub(win, 'open').callsFake((targetUrl) => { win.location.href = targetUrl }) }) // 移除所有a标签的_blank target属性 cy.document().then(doc => { doc.querySelectorAll('a[target="_blank"]').forEach(link => { link.removeAttribute('target') }) }) })注意需要先在
cypress.config.js中关闭浏览器web安全限制,否则跨域跳转会被Chromium默认安全策略拦截:module.exports = { e2e: { chromeWebSecurity: false, // 其余配置 } }从根源关闭Outlook SDK的弹窗登录模式
如果你的应用使用微软官方MSAL库实现Outlook集成,直接在测试环境的MSAL初始化配置中,把默认的弹窗登录改成重定向登录,从代码层面避免新窗口触发:// 测试环境MSAL配置 const msalConfig = { auth: { clientId: "你的应用ID", // 其余鉴权参数 }, cache: { /* 缓存配置 */ } } // 登录时不要调用loginPopup,改用loginRedirect myMSALObj.loginRedirect(loginRequest)也可以直接抓出自有应用触发Outlook登录时的目标跳转地址,跳过前端点击触发弹窗的环节,直接用
cy.visit(登录地址)在当前页进入登录流程。适配高版本Cypress的多窗口捕获逻辑
升级Cypress到12.0及以上版本,通过stub捕获新窗口的目标地址,再手动在当前页加载对应地址:cy.visit('你的自有应用测试地址') // 提前埋点监听window.open调用 cy.window().then(win => { cy.stub(win, 'open').as('outlookPopupOpen') }) // 点击触发Outlook登录的按钮 cy.get('[data-testid="outlook-login-btn"]').click() // 拿到弹窗的目标登录地址,直接在当前页访问 cy.get('@outlookPopupOpen').should('have.been.called').then(popupStub => { const outlookLoginUrl = popupStub.args[0][0] cy.visit(outlookLoginUrl) // 后续在当前页执行账号输入、授权等登录操作即可 })测试环境Mock Outlook登录回调
如果测试目标是自有应用和Outlook的集成逻辑,不需要验证微软侧的登录页功能,可以直接拦截跳转到Outlook域名的请求,构造模拟的登录成功鉴权信息返回给前端,跳过真实Outlook页面加载环节。这个方案稳定性最高,不会受微软登录页UI变动、账号风控、跨域限制的影响。
如果配置后依然出现静默中断,启动Cypress的浏览器开发者工具检查控制台报错,大概率是第三方Cookie拦截导致的鉴权流程中断,可以在Cypress浏览器启动配置中加参数关闭对应限制:
// cypress.config.js 中配置浏览器启动参数 setupNodeEvents(on, config) { on('before:browser:launch', (browser, launchOptions) => { if (browser.family === 'chromium') { launchOptions.args.push('--disable-third-party-cookie-blocking') launchOptions.args.push('--disable-features=SameSiteByDefaultCookies') } return launchOptions }) }
内容的提问来源于stack exchange,提问作者Blaxin_kun

