Cypress 对 Vue 3 进行测试以检查 i18n 语言转换器

Wil*_*urb 2 vue-i18n cypress vuejs3 cypress-component-testing

在我的 Vue 3 应用程序中,用户可以为自己制作多语言页面。他们可以决定其页面上可用的语言。可用的语言是从 API 加载的。

语言加载到 Pinia 存储中,LanguageSwitcher.vue 组件根据浏览器设置、URL 中的语言变量、默认区域设置和可用语言加载默认语言。所有这些都需要严格的赛普拉斯测试,其中之一是确保页面上显示的所选语言实际上是所选的语言。但是我如何从 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>
Run Code Online (Sandbox Code Playgroud)

我的测试加载 i18n 并应该检查当前语言(但不知道如何做到这一点)

__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       //<---thought if I declare it here maybe the test could access it
  beforeEach(() => {
    //list alle the available languages
    const availableMessages = { ru, en, ro }

    //load available languages
    i18n = createI18n({
      legacy: false,
      fallbackLocale: ro,
      locale: ro,
      globalInjection: true,
      messages: availableMessages
    })

    //mount component with the new i18n object
    cy.mount(LocaleSwitcher, { global: { plugins : [ i18n ]}})
  })


  it('Check if bold language is active language', () => {
    i18n.locale = 'ru'                    //<--- like so, but no
    //check of all links shown are unique
    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')
    })
  })
})
Run Code Online (Sandbox Code Playgroud)

我试图找到它在哪里global.plugins.i18n,但我所有的搜索都一无所获。那么我如何访问 Cypress 中当前安装的组件中的 i18n 并读取i18n.locale

包.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"
  }
}
Run Code Online (Sandbox Code Playgroud)

赛普拉斯.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'
    }
  }
})
Run Code Online (Sandbox Code Playgroud)

赛普拉斯/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);

//list alle the available languages
const availableMessages = { en, de, nl }

const i18n = createI18n({
  legacy: false,
  fallbackLocale: en,
  locale: nl,
  globalInjection: true,
  messages: availableMessages
})

Cypress.Commands.add('mount', (component, options = {}) => {
  // Setup options object
  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 || []

  /* Add any global plugins */

  //check if array is empty, if not assume there is already an i18n object there
  if (options.global.plugins[0] == undefined ) {
    //for testing the language selector this needs to be inserted in that test
    options.global.plugins.push(i18n)
  }
  options.global.plugins.push(pinia)

  return mount(component, options)
})
Run Code Online (Sandbox Code Playgroud)

Tes*_*ick 5

locale 属性是从 访问的Cypress.vue.$i18n.locale

\n

Cypress github 存储库中有一个示例,此处cypress/npm/vue/cypress/component/advanced/i18n\n/spec.js

\n

接近您的要求的示例规格是

\n
/// <reference types="cypress" />\nimport TranslatedMessageI18nBlock from \'./TranslatedI18nMessage.vue\'\nimport { createI18n } from \'vue-i18n\'\nimport { mount } from \'@cypress/vue\'\nimport messages from \'./translations.json\'\n\ndescribe(\'VueI18n\', () => {\n  describe(\'with i18n block\', () => {\n\n    it(\'shows HelloWorld for all locale\', () => {\n\n      const i18n = createI18n({ \n        locale: \'en\', \n        messages \n      })\n      mount(TranslatedMessageI18nBlock, { global: { plugins: [i18n] } })\n\n      cy.then(() => Cypress.vue.$i18n.locale = \'ru\')\n      cy.contains(\'\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82 \xd0\xbc\xd0\xb8\xd1\x80\')\n\n      cy.then(() => Cypress.vue.$i18n.locale = \'ja\')\n      cy.contains(\'\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xe3\x81\xaf\xe3\x80\x81\xe4\xb8\x96\xe7\x95\x8c\')\n      \n      cy.then(() => Cypress.vue.$i18n.locale = \'fa\')\n      cy.contains(\'\xd8\xb3\xd9\x84\xd8\xa7\xd9\x85 \xd8\xaf\xd9\x86\xdb\x8c\xd8\xa7\')\n            \n      cy.then(() => Cypress.vue.$i18n.locale = \'en\')\n      cy.contains(\'hello world!\')\n    })\n  })\n})\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,我正在.then()回调内设置区域设置,以便更改在命令队列中按顺序进行。

\n

locale否则,测试将在队列开始运行之前触发最后一个更新 (\'en\'),并且第一个cy.contains()更新将失败。

\n

在此输入图像描述

\n
\n

@cypress/vue 公开全局变量的源代码

\n

参考cypress/npm/vue/src/index.ts

\n
// mount the component using VTU and return the wrapper in Cypress.VueWrapper\nconst wrapper = VTUmount(componentOptions, { attachTo: componentNode, ...options })\n\nCypress.vueWrapper = wrapper as VueWrapper<ComponentPublicInstance>\nCypress.vue = wrapper.vm as ComponentPublicInstance\n
Run Code Online (Sandbox Code Playgroud)\n
\n

package.json 与您自己的进行比较

\n
{\n  "name": "vue-project",\n  "version": "0.0.0",\n  "private": true,\n  "type": "module",\n  "scripts": {\n    "dev": "vite",\n    "build": "vite build",\n    "preview": "vite preview",\n    "test:e2e": "start-server-and-test preview http://localhost:4173 \'cypress run --e2e\'",\n    "test:e2e:dev": "start-server-and-test \'vite dev --port 4173\' http://localhost:4173 \'cypress open --e2e\'",\n    "test:unit": "cypress run --component",\n    "test:unit:dev": "cypress open --component"\n  },\n  "devDependencies": {\n    "@cypress/vue": "^6.0.0",\n    "vue": "^3.4.15",\n    "@vitejs/plugin-vue": "^5.0.3",\n    "cypress": "^13.6.3",\n    "start-server-and-test": "^2.0.3",\n    "vite": "^5.0.11",\n    "vue-i18n": "^9.9.1"\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n