You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue3项目中如何在Cypress中获取i18n当前选中语言

如何在Cypress组件测试中访问Vue I18n的当前语言

我在Vue3应用中实现了多语言功能,用户可自定义可用语言,语言数据从API加载后存储在Pinia状态管理库中。LanguageSwitcher.vue组件会根据浏览器设置、URL语言参数、默认区域设置及可用语言自动加载默认语言。现在需要用Cypress进行组件测试,其中一项测试要求验证页面上加粗显示的语言确实是当前激活的语言,但不清楚如何在Cypress中获取i18n的当前选中语言。

LanguageSwitcher.vue组件代码

</script>
<template>
  <div data-testid="localeSwitcher">
    <span v-if="getAvailableLocales().length > 1">
      <span v-for="(locale, i) in getAvailableLocales()" :key="`locale-${locale}`">
        <span v-if="i != 0" class="has-text-warning-dark"> | </span>
        <a  @click="setLocale(locale)" :class="[{ 'has-text-weight-bold' : ($i18n.locale === locale)}, 'has-text-warning-dark']">
          {{ locale.toUpperCase() }}
        </a>
      </span>
    </span>
  </div>
</template>

测试文件(test/LanguageSwitcher.cy.js)

import LanguageSwitcher from '../items/LanguageSwitcher.vue'
import { createI18n } from 'vue-i18n'
import { mount } from '@cypress/vue'
import en from '../../locales/en.json'
import ru from '../../locales/ru.json'
import ro from '../../locales/ro.json'

describe('Test the LocaleSwitcher Languages selected',() => {
  let i18n       
  beforeEach(() => {
    const availableMessages = { ru, en, ro }

    i18n = createI18n({
      legacy: false,
      fallbackLocale: 'ro', // 注意:这里应该传入字符串,而非导入的JSON对象
      locale: 'ro', // 同上
      globalInjection: true,
      messages: availableMessages
    })

    cy.mount(LanguageSwitcher, { global: { plugins : [ i18n ]}})
  })

  it('Check if bold language is active language', () => {
    // 组合式API下需修改locale的value属性
    i18n.global.locale.value = 'ru'

    cy.get('*[class^="has-text-weight-bold"]').should('have.length', 1)
    cy.get('*[class^="has-text-weight-bold"]').each(($a) => {
      expect($a.text()).to.have.string('RU')
    })

    // 验证当前i18n的locale值
    cy.getComponent().then(wrapper => {
      expect(wrapper.vm.$i18n.locale.value).to.equal('ru')
    })
  })
})

相关配置文件

packages.json

{
  "name": "web-shop",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "test:e2e": "start-server-and-test preview http://localhost:4173 'cypress run --e2e'",
    "test:e2e:dev": "start-server-and-test 'vite dev --port 4173' http://localhost:4173 'cypress open --e2e'",
    "test:unit": "cypress run --component",
    "test:unit:dev": "cypress open --component",
    "css-deploy": "npm run css-build && npm run css-postcss",
    "css-build": "node-sass --omit-source-map-url src/assets/_sass/main.scss src/assets/css/main.css",
    "css-postcss": "postcss --use autoprefixer --output src/assets/css/main.css src/assets/css/main.css",
    "css-watch": "npm run css-build -- --watch",
    "deploy": "npm run css-deploy",
    "start": "npm-run-all --parallel css-watch"
  },
  "dependencies": {
    "bulma": "^0.9.4",
    "fork-awesome": "^1.2.0",
    "pinia": "^2.1.4",
    "vue": "^3.3.4",
    "vue-i18n": "^9"
  },
  "devDependencies": {
    "@cypress/vue": "^6.0.0",
    "@npmcli/fs": "latest",
    "@vitejs/plugin-vue": "^4.2.3",
    "@vitejs/plugin-vue-jsx": "^3.0.1",
    "cypress": "^13.2.0",
    "node-sass": "latest",
    "start-server-and-test": "^2.0.0",
    "vite": "^4.4.6"
  }
}

cypress.config.js

const { defineConfig } = require('cypress')

module.exports = defineConfig({
  defaultCommandTimeout: 10000,
  e2e: {
    specPattern: 'cypress/e2e/**/*.{cy,spec}.{js,jsx,ts,tsx}',
    baseUrl: 'http://localhost:4173'
  },
  component: {
    specPattern: 'src/**/__tests__/*.{cy,spec}.{js,ts,jsx,tsx}',
    devServer: {
      framework: 'vue',
      bundler: 'vite'
    }
  }
})

cypress/support/components.js

import './commands'
import { mount } from 'cypress/vue'
import { createPinia,  setActivePinia } from 'pinia'
import { useBusinessInfoStore } from '../../src/stores/businessInfo.js'
import { createI18n } from 'vue-i18n'
import en from '../../src/locales/en.json'
import de from '../../src/locales/de.json'
import nl from '../../src/locales/nl.json'

let pinia = createPinia();
setActivePinia(pinia);

const availableMessages = { en, de, nl }

const i18n = createI18n({
  legacy: false,
  fallbackLocale: 'en', // 修正为字符串
  locale: 'nl', // 修正为字符串
  globalInjection: true,
  messages: availableMessages
})

// 可选:将i18n挂载到Cypress全局,方便测试中直接访问
Cypress.i18n = i18n

Cypress.Commands.add('mount', (component, options = {}) => {
  options.global = options.global || {}
  options.global.stubs = options.global.stubs || {}
  options.global.stubs['transition'] = false
  options.global.components = options.global.components || {}
  options.global.plugins = options.global.plugins || []

  if (!options.global.plugins.length) {
    options.global.plugins.push(i18n)
  }
  options.global.plugins.push(pinia)

  return mount(component, options)
})

解决方案

方法1:通过组件实例访问i18n

Cypress的cy.getComponent()方法可获取挂载的Vue组件实例,通过实例的$i18n属性访问当前locale(Vue I18n v9中locale是Ref对象,需读取value):

cy.getComponent().then(wrapper => {
  expect(wrapper.vm.$i18n.locale.value).to.equal('ru')
})

方法2:直接操作测试中创建的i18n实例

测试用例中已创建i18n实例,直接修改global.locale.value切换语言,同时可直接读取该值:

// 修改语言
i18n.global.locale.value = 'ru'
// 验证当前语言
expect(i18n.global.locale.value).to.equal('ru')

方法3:全局暴露i18n实例

在cypress/support/components.js中将i18n挂载到Cypress全局对象,所有测试文件可直接访问:

// 在components.js中添加
Cypress.i18n = i18n

测试中使用:

Cypress.i18n.global.locale.value = 'ru'
expect(Cypress.i18n.global.locale.value).to.equal('ru')

注意事项

  • Vue I18n v9(组合式API模式)下,locale是Ref对象,必须通过value属性修改/读取,不能直接赋值i18n.locale = 'ru'。
  • fallbackLocale和locale配置项需传入字符串(如'ro'),而非导入的JSON文件对象。
  • 原测试中cy.mount(LocaleSwitcher)存在拼写错误,应改为cy.mount(LanguageSwitcher)。

内容的提问来源于stack exchange,提问作者St. Jan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 05:14:52