正在加载

测试

下表概述了可能的测试文件位置以及如何调用它们

测试运行器 测试位置 运行器命令(工作目录是 Kibana 根目录)
Jest **/*.test.{js,mjs,ts,tsx} yarn test:jest [测试路径]
Jest (集成) **/integration_tests/**/*.test.{js,mjs,ts,tsx} yarn test:jest_integration [测试路径]
功能 test/**/config.js x-pack/test/**/config.js node scripts/functional_tests_server --config [目录]/config.js node scripts/functional_test_runner --config [目录]/config.js --grep=regexp

测试运行器参数:- 在适用的情况下,可选参数 --grep=regexp 将仅运行其描述与正则表达式匹配的测试或测试套件。 - [测试路径] 是测试文件的相对路径。

Kibana 主要使用 Jest 进行单元测试。每个插件或包都定义了一个 jest.config.js,它扩展了 @kbn/test 包提供的预设。除非您打算运行项目中的所有单元测试,否则提供您正在测试的插件或包的 Jest 配置文件是最有效的。

yarn jest --config src/platform/plugins/shared/dashboard/jest.config.js

当在整个存储库中导航时,可以使用脚本来提供更好的测试用户体验。 要在当前工作目录中运行测试,请使用 yarn test:jest。 与 Jest CLI 类似,您还可以提供一个路径来确定要运行的测试。

kibana/src/platform/plugins/shared/dashboard/server$ yarn test:jest #or
kibana/src/platform/plugins/shared/dashboard$ yarn test:jest server #or
kibana$ yarn test:jest src/platform/plugins/shared/dashboard/server

提供给 test:jest 的任何其他选项都将传递到 Jest CLI,并且始终会输出生成的 Jest 命令。

kibana/src/platform/plugins/shared/dashboard/server$ yarn test:jest --coverage

# is equivalent to

yarn jest --coverage --verbose --config /home/tyler/elastic/kibana/src/platform/plugins/shared/dashboard/jest.config.js server

您可以为单个插件生成代码覆盖率报告。

yarn jest --coverage --config src/platform/plugins/shared/console/jest.config.js

Html 报告位于 target/kibana-coverage/jest/path/to/plugin

查看功能测试,了解更多关于如何为 Kibana 核心和插件运行和开发功能测试的信息。

您还可以查看Scripts README.md,了解更多关于使用我们提供的节点脚本来构建 Kibana、运行集成测试以及在您开发时启动 Kibana 和 Elasticsearch 的信息。

我们使用功能测试来确保 Kibana UI 按预期工作。它通过自动化用户交互取代了数小时的手动测试。为了更好地控制我们的功能测试环境,并使插件作者更容易访问,Kibana 使用了一个名为 FunctionalTestRunner 的工具。

FunctionalTestRunner (FTR) 非常简陋,它的大部分功能都来自其配置文件。 Kibana 存储库包含许多 FTR 配置文件,这些配置文件对 Kibana 服务器或 Elasticsearch 使用略有不同的配置,具有不同的测试文件,并且可能存在其他配置差异。 FTR 配置文件根据测试区域和分发类型组织在清单文件中:serverless: - ftr_base_serverless_configs.yml - ftr_oblt_serverless_configs.yml - ftr_security_serverless_configs.yml - ftr_search_serverless_configs.yml stateful: - ftr_platform_stateful_configs.yml - ftr_oblt_stateful_configs.yml - ftr_security_stateful_configs.yml - ftr_search_stateful_configs.yml 如果您在 Kibana 存储库之外编写插件,您将拥有自己的配置文件。 有关更多信息,请参阅Kibana 存储库外部插件的功能测试

根据您的目标,有三种方法可以运行测试

  1. 最简单的选项

    • 描述:启动 Kibana 和 Elasticsearch 服务器,然后运行测试。由于服务器启动时间慢,因此多次运行测试时速度会慢得多。 推荐用于单次运行。

    • node scripts/functional_tests

      • 在一个命令中完成所有操作,包括在本地运行 Elasticsearch 和 Kibana
      • 在测试运行后拆除所有内容
      • 退出代码报告测试的成功/失败
  2. 最适合开发

    • 描述:两个命令,在单独的终端中运行,将长时间运行和缓慢的组件与短暂和快速的组件分开。 可以更快地重新运行测试,并且这仍然在本地运行 Elasticsearch 和 Kibana。

    • node scripts/functional_tests_server

      • 启动 Elasticsearch 和 Kibana 服务器
      • 启动缓慢
      • 可以重复使用多次执行测试,从而节省重新运行测试的时间
      • 当检测到相关更改时,自动重启 Kibana 服务器
    • node scripts/functional_test_runner

      • 针对由 node scripts/functional_tests_server 启动的 Kibana 和 Elasticsearch 服务器运行测试
      • 退出代码报告测试的成功或失败
  3. 自定义选项

    • 描述:针对以其他方式启动的 Elasticsearch 和 Kibana 实例运行测试(例如,Elastic Cloud 或您以某种其他方式管理的实例)。

    • 仅执行功能测试

    • Elasticsearch 和 Kibana 的 URL、凭据等通过环境变量指定

    • 当针对 Elastic Cloud 实例运行时,需要额外的环境变量 TEST_CLOUDES_SECURITY_ENABLED

    • 您必须运行与您正在测试的 Kibana 版本相同的测试分支。 要针对以前的次要版本运行,请使用选项 --es-version <实例版本>

    • 要运行特定配置,请使用选项 --config <配置文件>

    • 这是一个针对 Elastic Cloud 实例运行的示例

      export TEST_KIBANA_URL=https://elastic:password@my-kbn-cluster.elastic-cloud.com:443
      export TEST_ES_URL=https://elastic:password@my-es-cluster.elastic-cloud.com:443
      
      export TEST_CLOUD=1
      export ES_SECURITY_ENABLED=1
      
      node scripts/functional_test_runner [--config <config>] [--es-version <instance version>]
      
    • 或者您可以覆盖 URL 的任何或所有这些单独部分,并将其他部分保留为默认值。

      export TEST_KIBANA_PROTOCOL=https
      export TEST_KIBANA_HOSTNAME=my-kibana-instance.internal.net
      export TEST_KIBANA_PORT=443
      export TEST_KIBANA_USER=kibana
      export TEST_KIBANA_PASS=<password>
      
      export TEST_ES_PROTOCOL=http
      export TEST_ES_HOSTNAME=my-es-cluster.internal.net
      export TEST_ES_PORT=9200
      export TEST_ES_USER=elastic
      export TEST_ES_PASS=<password>
      node scripts/functional_test_runner
      
    • Selenium 测试在 CI 上以无头模式运行。 在本地,相同的测试将在真正的浏览器中执行。 您可以通过设置环境变量来激活无头模式

      export TEST_BROWSER_HEADLESS=1
      
    • 如果您使用的是 Google Chrome,您可以降低本地网络连接速度以验证测试稳定性

      export TEST_THROTTLE_NETWORK=1
      
    • 当针对 Cloud 部署运行时,某些测试不适用。 要跳过不适用的测试,请使用 --exclude-tag。

      node scripts/functional_test_runner --exclude-tag skipCloud
      node scripts/functional_test_runner --exclude-tag skipMKI
      

当不带任何参数运行时,FunctionalTestRunner 会自动加载标准位置的配置,但您可以使用 --config 标志覆盖该行为。 使用多个 --config 参数列出配置。

  • --config test/functional/apps/app-name/config.js 启动 Elasticsearch 和 Kibana 服务器,并将 WebDriver 测试配置为在 Chrome 中为特定应用程序运行。 例如,--config test/functional/apps/home/config.js 启动 Elasticsearch 和 Kibana 服务器,并将 WebDriver 测试配置为在 Chrome 中为 home 应用程序运行。
  • --config test/functional/config.firefox.js 启动 Elasticsearch 和 Kibana 服务器,并将 WebDriver 测试配置为在 Firefox 中运行。
  • --config test/api_integration/config.js 启动 Elasticsearch 和 Kibana 服务器,并使用 api 集成测试配置。
  • --config test/accessibility/config.ts 启动 Elasticsearch 和 Kibana 服务器,并将 WebDriver 测试配置为使用 axe 运行辅助功能审计。

还有 --bail--grep 的命令行标志,它们的行为就像它们的 mocha 对应项一样。 例如,使用 --grep=foo 仅运行与正则表达式匹配的测试。

还可以使用 --quiet--debug--verbose 标志自定义日志记录。

还有像 --include 这样的选项,可以仅运行在单个文件或一组文件中定义的测试。

运行 node scripts/functional_test_runner --help 以查看所有可用选项。

测试是用 mocha 编写的,使用 @kbn/expect 进行断言。

我们使用 WebDriver 协议,借助 chromedrivergeckodriver 在 Chrome 和 Firefox 中运行测试。 当 FunctionalTestRunner 启动时,远程服务会创建一个新的 webdriver 会话,该会话会启动驱动程序和一个精简的浏览器实例。 我们使用 browser 服务和 webElementWrapper 类来包装 Webdriver API

FunctionalTestRunner 使用 babel 自动转换功能测试,以便测试可以使用与 Kibana 源代码相同的 ECMAScript 功能。 请参阅 STYLEGUIDE.mdx

提供者

FunctionalTestRunner 运行的代码被包装在一个函数中,因此可以通过配置文件传递并进行参数化。 这些 Provider 函数中的任何一个都可以是异步的,并且应该返回/解析为它们要提供的值。 Provider 函数将始终使用单个参数调用:一个 provider API(参见Provider API 章节)。

一个配置提供者

// config and test files use `export default`
export default function (/* { providerAPI } */) {
  return {
    // ...
  }
}
服务
服务是一个使用 FtrService 的子类创建的命名单例。 测试和其他服务可以通过按名称请求它们来检索服务实例。 除了 mocha API 之外的所有功能都通过服务公开。 当您编写自己的功能测试时,请检查是否有现有服务可以帮助您执行交互,并为尚未编码在服务中的交互添加新服务。
服务提供者
出于遗留目的,以及当创建 FtrService 的子类不方便时,您还可以使用“服务提供者”来创建服务。 这些是创建服务实例并返回它们的函数。 这些实例会被缓存并提供给测试。 目前,这些提供者也可以返回服务实例的 Promise,允许服务在测试运行之前进行一些设置工作。 我们预计在不久的将来完全弃用和移除对异步服务提供者的支持,而是要求服务使用 lifecycle 服务在测试之前运行设置。 对于返回 FtrService 之外的类实例的提供者,我们可能会尽可能长时间地保持支持。
页面对象
页面对象在功能上等同于服务,只是它们以稍微不同的机制加载,并且通常与服务分开定义。 当您编写自己的功能测试时,您可能希望将某些服务编写为页面对象,但这不是必需的。
测试文件
FunctionalTestRunner 的主要目的是执行测试文件。 这些文件导出一个测试提供者,该提供者使用 Provider API 调用,但不期望返回一个值。 相反,测试提供者使用 mocha 的 BDD 接口定义一个套件。
测试套件
测试套件是通过调用 describe() 定义的测试集合,然后通过调用 it()before()beforeEach() 等填充测试和设置/拆卸钩子。每个测试文件必须仅定义一个顶级测试套件,并且测试套件可以根据需要拥有任意数量的嵌套测试套件。
标签

describe() 函数中使用标签对功能测试进行分组。标签包括

  • ciGroup{{id}} - 将测试套件分配给特定的 CI 工作者
  • skipCloudskipFirefox - 将测试套件从 Cloud 或 Firefox 上运行中排除
  • includeFirefox - 对在 Chrome 和 Firefox 上运行的测试进行分组
跨浏览器测试
在 CI 上,所有功能测试默认在 Chrome 中执行。要也针对 Firefox 运行一个套件,请分配 includeFirefox 标签
// on CI test suite will be run twice: in Chrome and Firefox
describe('My Cross-browser Test Suite', function () {
  this.tags('includeFirefox');

  it('My First Test');
}

如果测试不适用于 Firefox,请分配 skipFirefox 标签。

要在本地的 Firefox 上运行测试,请使用 config.firefox.js

node scripts/functional_test_runner --config test/functional/config.firefox.js

测试应该在积极的安全边界条件下运行,这意味着它们应该以所需的(并且已记录的)最小权限运行,而不是以超级用户身份运行。 这可以防止发生额外的权限意外地成为执行相同操作所必需的类型的回归。

功能 UI 测试现在默认使用名为 test_user 的用户登录,并且可以动态更改此用户的角色,而无需登录和退出。

为了实现这一点,引入了一个名为 createTestUserService 的新服务(参见 packages/kbn-ftr-common-functional-ui-services/services/security/test_user.ts)。 此测试用户服务的目的是创建在测试配置文件中定义的角色并设置 setRoles() 或 restoreDefaults()。

下面是如何像下面定义的那样设置角色的示例

await security.testUser.setRoles(['kibana_user', 'kibana_date_nanos']);

在这里,我们将 test_user 设置为拥有 kibana_user 角色,并且还拥有对特定数据索引 (kibana_date_nanos) 的角色访问权限。

测试通常应该在 before() 中设置 setRoles(),并在 after() 中设置 restoreDefaults()。

这个带注释的示例文件显示了每个测试套件使用的基本结构。 它首先导入 @kbn/expect 并定义其默认导出:一个匿名的测试提供者。 然后,测试提供者解构 Provider API 以获取 getService()getPageObjects() 函数。 它使用这些函数来收集此套件的依赖项。 测试文件的其余部分对于 mocha.js 用户来说看起来非常正常。 describe()it()before() 和其他类似函数用于定义恰好通过服务和 PageObject 类型的对象自动执行浏览器的套件。

import expect from '@kbn/expect';
// test files must `export default` a function that defines a test suite
export default function ({ getService, getPageObject }) {

  // most test files will start off by loading some services
  const retry = getService('retry');
  const testSubjects = getService('testSubjects');
  const esArchiver = getService('esArchiver');
  const kibanaServer = getService('kibanaServer');

  // for historical reasons, PageObjects are loaded in a single API call
  // and returned on an object with a key/value for each requested PageObject
  const PageObjects = getPageObjects(['common', 'visualize']);

  // every file must define a top-level suite before defining hooks/tests
  describe('My Test Suite', () => {

    // most suites start with a before hook that navigates to a specific
    // app/page and restores some archives into {es} with esArchiver
    before(async () => {
      await Promise.all([
        // start by clearing Saved Objects from the .kibana index
        await kibanaServer.savedObjects.cleanStandardList();
        // load some basic log data only if the index doesn't exist
        esArchiver.loadIfNeeded('src/platform/test/functional/fixtures/es_archiver/makelogs')
      ]);
      // go to the page described by `apps.visualize` in the config
      await PageObjects.common.navigateTo('visualize');
    });

    // right after the before() hook definition, add the teardown steps
    // that will tidy up {es} for other test suites
    after(async () => {
      // we clear Kibana Saved Objects but not the makelogs
      // archive because we don't make any changes to it, and subsequent
      // suites could use it if they call `.loadIfNeeded()`.
      await kibanaServer.savedObjects.cleanStandardList();
    });

    // This series of tests illustrate how tests generally verify
    // one step of a larger process and then move on to the next in
    // a new test, each step building on top of the previous
    it('Vis Listing Page is empty');
    it('Create a new vis');
    it('Shows new vis in listing page');
    it('Opens the saved vis');
    it('Respects time filter changes');
    it(...
  });

}

所有提供者的第一个也是唯一一个参数是 Provider API 对象。 此对象可用于加载服务/页面对象和配置/测试文件。

在配置文件中,API 具有以下属性

log
一个已准备好使用的 ToolingLog 实例
readConfigFile(path)
返回一个 Promise,该 Promise 将解析为 Config 实例,该实例提供来自 path 处配置文件的值

在服务和 PageObject 提供者中,API 是

getService(name)
按名称加载并返回服务的单例实例
getPageObjects(names)
加载 PageObject 的单例实例,并将它们收集到一个对象上,其中每个名称都是该 PageObject 单例实例的键

在测试提供者中,API 与服务提供者 API 完全相同,但具有一个额外的方法

loadTestFile(path)
就地加载路径处的测试文件。 使用此方法将其他文件中的套件嵌套到更高级别的套件中

FunctionalTestRunner 带有三个内置服务

config
  • 使用 config.get(path) 从配置文件中读取任何值
log
  • ToolingLog 实例是可读的流。 此服务提供的实例会自动通过 FunctionalTestRunner CLI 管道传输到 stdout
  • log.verbose()log.debug()log.info()log.warning() 的工作方式与 console.log 类似,但会产生更有组织的输出
lifecycle
  • 主要设计用于服务中
  • 公开用于基本协调的生命周期事件。 处理程序可以返回 Promise 并异步解析/失败
  • 阶段包括:beforeLoadTestsbeforeTestsbeforeEachTestcleanup

Kibana 功能测试定义了测试使用的大部分实际功能。

browser
  • remote 服务的更高级别包装器,它公开了可用的浏览器操作
  • 常用方法
  • browser.getWindowSize()
  • browser.refresh()
testSubjects
  • 测试主题是专门标记为从测试中选择的元素
  • 尽可能使用 testSubjects 而不是 CSS 选择器
  • 用法
  • 使用 data-test-subj 属性标记您的测试主题

html <div id="container”> <button id="clickMe” data-test-subj=”containerButton” /> </div>

  • 使用 testSubjects 辅助函数单击此按钮

js await testSubjects.click(‘containerButton’);

  • 常用方法

    • testSubjects.find(testSubjectSelector) - 在页面中查找测试主题;如果在一段时间后找不到它,则抛出异常
    • testSubjects.click(testSubjectSelector) - 单击页面中的测试主题;如果在一段时间后找不到它,则抛出异常
find
  • 用于记录和管理超时的 remote.findBy* 方法的辅助函数
  • 常用方法
  • find.byCssSelector()
  • find.allByCssSelector()
retry
  • 用于重试操作的辅助函数
  • 常用方法
  • retry.try(fn, onFailureBlock) - 在循环中执行 fn,直到它成功或默认超时时间到期。 可选的 onFailureBlock 在每次重试尝试之前执行。
  • retry.tryForTime(ms, fn, onFailureBlock) - 在循环中执行 fn,直到它成功或 ms 毫秒到期。 可选的 onFailureBlock 在每次重试尝试之前执行。
kibanaServer
  • 用于与 Kibana 服务器交互的辅助函数
  • 常用方法
  • kibanaServer.uiSettings.update()
  • kibanaServer.version.get()
  • kibanaServer.status.getOverallState()
esArchiver
  • 加载/卸载使用 esArchiver 创建的存档
  • 常用方法
  • esArchiver.load(path)
  • esArchiver.loadIfNeeded(path)
  • esArchiver.unload(path)

可以在这里找到功能测试中使用的服务的完整列表:test/functional/services

底层实用程序
  • es
  • Elasticsearch 客户端
  • 更高级别的选项:kibanaServer.uiSettingsesArchiver
  • remote

    • WebDriver 类的实例
    • 负责与浏览器的所有通信
    • 要执行浏览器操作,请使用 remote 服务
    • 对于搜索和操作 DOM 元素,请使用 testSubjectsfind 服务
    • 有关完整的 API,请参见 selenium-webdriver 文档

服务是有意通用的。 它们实际上可以是任何东西(甚至什么都没有)。 某些服务具有用于与特定类型的 UI 元素(如 pointSeriesVis)交互的辅助函数,而其他服务则更基础,例如 logconfig。 无论何时要以可重用的包形式提供某些功能,请考虑创建一个自定义服务。

要创建自定义服务 somethingUseful

  • 创建一个类似于以下内容的 test/functional/services/something_useful.js 文件

    // Services are defined by Provider functions that receive the ServiceProviderAPI
    export function SomethingUsefulProvider({ getService }) {
      const log = getService('log');
    
      class SomethingUseful {
        doSomething() {
        }
      }
      return new SomethingUseful();
    }
    
  • services/index.js 重新导出您的提供者

  • 将其导入到 src/functional/config.base.js 并将其添加到服务配置中

    import { SomethingUsefulProvider } from './services';
    
    export default function () {
      return {
        // … truncated ...
        services: {
          somethingUseful: SomethingUsefulProvider
        }
      }
    }
    

每个 PageObject 的目的是非常不言自明的。 可视化 PageObject 提供了用于与可视化应用程序交互的辅助函数,仪表板对于仪表板应用程序也是如此,依此类推。

一个例外是“common” PageObject。 从 intern 实现继承而来,common PageObject 是一个跨页面有用的辅助函数的集合。 现在我们有了可共享的服务,并且这些服务可以与其他 FunctionalTestRunner 配置共享,我们将继续将功能从 common PageObject 移到服务中。

请将新方法添加到现有或新服务中,而不是进一步扩展 CommonPage 类。

请记住,您无法在文件中运行单个测试(it 块),因为需要运行整个 describe。 一个文件中应该只有一个顶级 describe

另一个重要的注意事项是通过注意计时来编写稳定的测试。 remote 上的所有方法都异步运行。 最好编写在 UI 上等待更改出现后再进入下一步的交互。

例如,与其编写一个简单地单击按钮的交互,不如编写一个具有更高层次目的的交互

错误示例:PageObjects.app.clickButton()

class AppPage {
  // what can people who call this method expect from the
  // UI after the promise resolves? Since the reaction to most
  // clicks is asynchronous the behavior is dependent on timing
  // and likely to cause test that fail unexpectedly
  async clickButton () {
    await testSubjects.click(‘menuButton’);
  }
}

良好示例:PageObjects.app.openMenu()

class AppPage {
  // unlike `clickButton()`, callers of `openMenu()` know
  // the state that the UI will be in before they move on to
  // the next step
  async openMenu () {
    await testSubjects.click(‘menuButton’);
    await testSubjects.exists(‘menu’);
  }
}

以这种方式编写将确保您的测试计时不会出现问题或基于交互后 UI 更新的假设。

从命令行运行

node --inspect-brk scripts/functional_test_runner

这会打印出一个 URL,您可以在 Chrome 中访问该 URL 并在浏览器中调试您的功能测试。

您还可以通过使用 --debug--verbose 标志运行 FunctionalTestRunner 来查看终端中的其他日志。 通过在您的测试中添加以下语句来添加更多日志

// load the log service
const log = getService(‘log’);

// log.debug only writes when using the `--debug` or `--verbose` flag.
log.debug(‘done clicking menu’);

在具有独立显卡的机器上运行测试的 macOS 用户可以通过更改终端模拟器的 GPU 设置来显着提高速度(高达 2 倍)。 在 iTerm2 中: * 打开首选项(Command + ,) * 在“常规”选项卡的“Magic”部分下,确保选中“GPU 渲染” * 打开“高级 GPU 设置…” * 取消选中“首选集成到离散 GPU”选项 * 重新启动 iTerm

如果你的功能测试不稳定(flaky),运维团队可能会跳过这些测试,并要求你在重新启用它们之前减少不稳定情况。这个过程通常包括查看相关 Github issue 上记录的失败情况,并找出需要在测试中等待的不正确的假设或条件。为了确定你的更改是否能减少测试失败的频率,你可以在 Flaky Test Runner 中运行你的测试。这个工具可以运行特定 ciGroup 的多达 500 次执行。要启动 Flaky Test Runner 的构建,创建一个包含你的更改的 PR,然后访问 https://ci-stats.kibana.dev/trigger_flaky_test_runner,选择你的 PR,选择你的测试所在的 CI Group,然后触发构建。

这将把你带到 Buildkite,你的构建将在那里运行,并告诉你它是否在任何执行中失败。

一个不稳定的测试可能只在 1000 次运行中失败一次,所以请记住这一点,并确保你使用足够的执行次数来真正证明测试不再不稳定。

Kibana 使用 Jest 进行单元测试。

Jest 测试与源代码文件存储在同一目录中,后缀为 .test.{js,mjs,ts,tsx}

每个插件和包都包含自己的 jest.config.js 文件来定义其根目录,以及对 @kbn/test 提供的 jest-preset 的任何覆盖。当处理单个插件或包时,你会发现运行 Jest 时提供配置文件会更有效率。

yarn jest --config src/platform/plugins/shared/discover/jest.config.js

为了编写这些测试,你需要注意两件主要的事情。第一件是 jest.mockjest.doMock 之间的区别,第二件是我们的 jest mocks file pattern。由于我们使用 babel-jest 运行 jsts 测试文件,因此这两种技术都是必需的,特别是对于在 Typescript 上实现的测试,以便从自动推断类型功能中受益。

这两种方法本质上是相同的,但是 jest.mock 调用将被提升到文件的顶部,并且只能引用以 mock 为前缀的变量。另一方面,jest.doMock 不会被提升,并且可以引用我们想要的几乎任何变量,但是我们必须确保这些被引用的变量在我们需要的时刻被实例化,这会将我们引导到下一节,我们将讨论我们的 jest mock 文件模式。

特别是在 typescript 中,在单元测试中使用 jest.doMock 调用,例如引用导入的类型,是很常见的。这样做会抛出任何错误,但是测试将会失败。其背后的原因是,尽管 jest.doMock 没有被 babel-jest 提升,但是我们引用的类型的导入将被提升到顶部,并且在我们调用函数时,该变量将不会被定义。

为了防止这种情况,我们开发了一个应该遵循的协议

  • 每个模块都可以在 mymodule.mock.ts 中提供一个标准 mock,以防其他测试可以从使用此处的定义中受益。这个文件不会有任何 jest.mock 调用,只有虚拟对象。
  • 每个测试都在 mymodule.test.mocks.ts 中定义其 mocks。这个文件可以从通用模块的 mocks 文件 (*.mock.ts) 导入相关的 mocks,并为每个 mock 调用 jest.mock。如果任何相关的虚拟 mock 对象需要通用化(并被其他测试使用),则可以直接在此文件中定义虚拟对象。
  • 每个测试都将从测试 mocks 文件 mymodule.test.mocks.ts 导入其 mocks。mymodule.test.ts 有一个像这样的导入:import * as Mocks from './mymodule.test.mocks', import { mockX } from './mymodule.test.mocks' 或只是 import './mymodule.test.mocks' 如果没有任何东西被导出以供使用。

标准的 yarn test 任务运行几个子任务,可能需要几分钟才能完成,这使得调试失败非常痛苦。为了减轻痛苦,专门的任务提供了运行测试的替代方法。

你也可以添加 --debug 选项,以便使用 --inspect-brk 标志运行 node。你需要连接一个远程调试器,例如 node-inspector 才能在此模式下继续。

即使使用 Kibana 插件生成器,我们也不强制你对插件进行单元测试的方式。请设置并使用你选择的工具。如果插件将位于 Kibana 仓库中,则必须使用 Jest

要编写可访问性测试,请使用提供的可访问性服务 getService('a11y')。可访问性测试编写起来相当简单,因为 axe 完成了大部分繁重的工作。导航到你需要测试的 UI,然后从之前导入的服务调用 testAppSnapshot(); 以确保 axe 没有发现任何失败。导航通过 UI 的每个部分以获得最佳覆盖。

一个示例测试可能看起来像这样

export default function ({ getService, getPageObjects }) {
  const { common, home } = getPageObjects(['common', 'home']);
  const a11y = getService('a11y'); /* this is the wrapping service around axe */

  describe('Kibana Home', () => {
    before(async () => {
      await common.navigateToApp('home'); /* navigates to the page we want to test */
    });

    it('Kibana Home view', async () => {
      await retry.waitFor(
        'home page visible',
        async () => await testSubjects.exists('homeApp')
      ); /* confirm you're on the correct page and that it's loaded */
      await a11y.testAppSnapshot(); /* this expects that there are no failures found by axe */
    });

    /**
     * If these tests were added by our QA team, tests that fail that require significant app code
     * changes to be fixed will be skipped with a corresponding issue label with more info
     */
    // Skipped due to https://github.com/elastic/kibana/issues/99999
    it.skip('all plugins view page meets a11y requirements', async () => {
      await home.clickAllKibanaPlugins();
      await a11y.testAppSnapshot();
    });

    /**
     * Testing all the versions and different views of of a page is important to get good
     * coverage. Things like empty states, different license levels, different permissions, and
     * loaded data can all significantly change the UI which necessitates their own test.
     */
    it('Add Kibana sample data page', async () => {
      await common.navigateToUrl('home', '/tutorial_directory/sampleData', {
        useActualUrl: true,
      });
      await a11y.testAppSnapshot();
    });
  });
}

要在本地运行测试

  1. 在一个终端窗口中运行

    node scripts/functional_tests_server --config test/accessibility/config.ts
    
  2. 当服务器打印出它已准备就绪时,在另一个终端窗口中运行

    node scripts/functional_test_runner.js --config test/accessibility/config.ts
    

要运行 x-pack 测试,将配置文件替换为 x-pack/test/accessibility/apps/{group1,group2,group3}/config.ts

测试是使用 axe 完成的。你可以使用浏览器插件运行与 CI 运行的相同内容

如果你以前从未见过失败,失败可能会让人感到困惑。以下是 CI 中出现的失败的分解

1)    Dashboard
       create dashboard button:

      Error: a11y report:

 VIOLATION
   [aria-hidden-focus]: Ensures aria-hidden elements do not contain focusable elements
     Help: https://dequeuniversity.com/rules/axe/3.5/aria-hidden-focus?application=axeAPI
     Elements:
       - <span aria-hidden="true"><button type="button">Submit</button></span>
       at Accessibility.testAxeReport (test/accessibility/services/a11y/a11y.ts:90:15)
       at Accessibility.testAppSnapshot (test/accessibility/services/a11y/a11y.ts:58:18)
       at process._tickCallback (internal/process/next_tick.js:68:7)
  • "Dashboard" 和 "create dashboard button" 是测试套件和特定失败测试的名称。
  • 总是用括号括起来,"[aria-hidden-focus]" 是失败的 axe 规则的名称,后跟简短描述。
  • "Help: <url>" 链接到该规则的 axe 文档,包括严重性、补救提示以及良好和不良的代码示例。
  • "Elements:" 指向 DOM 中失败的来源(使用 HTML 语法)。在此示例中,问题来自具有 aria-hidden="true" 属性和嵌套的 <button> 标签的 span。如果选择器太复杂而无法找到问题的根源,请使用前面提到的浏览器插件来定位它。如果你大致知道问题出在哪里,你也可以尝试向页面添加唯一的 ID 以缩小位置。
  • 堆栈跟踪指向 axe 的内部。堆栈跟踪的存在是为了以防测试失败是 axe 中的错误,而不是你的代码中的错误,尽管这种情况不太可能发生。

打包测试使用 Vagrant 虚拟机作为主机,并使用 Ansible 进行配置和断言。Kibana 发行版从目标文件夹复制到每个 VM 中并安装,以及所需的依赖项。

  • Ansible

    # Ubuntu
    sudo apt-get install python3-pip libarchive-tools
    pip3 install --user ansible
    
    # Darwin
    brew install python3
    pip3 install --user ansible
    
  • Vagrant

  • Virtualbox

主机名 IP 描述
deb 192.168.56.5 Kibana 的 deb 包的安装
rpm 192.168.56.6 Kibana 的 rpm 包的安装
docker 192.168.56.7 Kibana 的 docker 镜像的安装
# Build distributions
node scripts/build --all-platforms --debug

cd src/platform/test/package

# Setup virtual machine and networking
vagrant up <hostname> --no-provision

# Install Kibana and run OS level tests
# This step can be repeated when adding new tests, it ensures machine state - installations won't run twice
vagrant provision <hostname>

# Running functional tests
node scripts/es snapshot \
  -E network.bind_host=127.0.0.1,192.168.56.1 \
  -E discovery.type=single-node \
  --license=trial
TEST_KIBANA_URL=http://elastic:changeme@<ip>:5601 \
TEST_ES_URL=http://elastic:changeme@192.168.56.1:9200 \
  node scripts/functional_test_runner.js --include-tag=smoke
vagrant destroy <hostname>

在 OS X 上测试 IE

注意: 从 7.9 版本开始,不再支持 IE11。

  • 下载 VMWare Fusion.
  • 下载适用于 VMWare 的 IE 虚拟机
  • 打开 VMWare 并转到 Window > Virtual Machine Library。解压缩虚拟机并将 .vmx 文件拖到你的 Virtual Machine Library 中。
  • 右键单击你刚添加到你的库中的虚拟机,然后选择 "Snapshots…",然后单击打开的模态框中的 "Take" 按钮。你可以在 VM 在 90 天后过期时回滚到此快照。
  • 在 System Preferences > Sharing 中,将你的计算机名称更改为简单的名称,例如 "computer"。
  • 使用 yarn start --host=computer.local 运行 Kibana(替换你的计算机名称)。
  • 现在你可以运行你的 VM,打开浏览器,然后导航到 http://computer.local:5601 以测试 Kibana。
  • 或者,你可以使用 browserstack
© . All rights reserved.