沙尘暴/e2etesttools

安装次数: 32,028

依赖项: 0

建议者: 0

安全: 0

星标: 8

关注者: 8

分支: 1

公开问题: 7

类型:neos-package


README

... 用于 Neos 和 Flow 项目。

对于 SYMFONY 项目,请参阅 README.Symfony.md

我们使用 Playwright 作为测试涉及真实浏览器的浏览器调度器。我们使用 Behat 作为编写所有类型 BDD 测试的测试框架。

  • 使用 Behat 测试 Fusion 代码的方法

  • 用于集成 Playwright 浏览器调度器和 Behat 测试框架的实用工具

架构

我们建议您大致浏览这部分内容,以了解整体架构的概述。只要您不进行深入修改,您不需要详细阅读。

运行行为测试的架构如下

   ╔╦══════════════════╦╗   1  ┌────────────────────┐
   ║│Behat Test Runner ├╬──────▶   E2E-Testrunner   │
   ║└──────────────────┘║      │(Playwright Server -│
   ║ Application Docker ║      │  Chrome Browser)   │
   ║  Container (SUT)   ║◀─────┤                    │
   ╚══════════╦═════════╝   2  └────────────────────┘
              │                                      
             3│                                      
   ┌──────────▼─────────┐                            
   │other services (DB, │                            
   │    Redis, ...)     │                            
   └────────────────────┘                            
  1. 我们将 Behat 测试运行器添加到开发或生产 App Docker 容器(SUT - 系统测试对象),这样 Behat 测试运行器就可以访问应用程序的任何代码,并具有与生产应用程序完全相同的环境、数据库和库版本。

  2. E2E 测试运行器包装 Playwright(这是一个浏览器调度器)并公开 HTTP API。它作为相关服务运行。Behat 通过 HTTP 与测试运行器通信(1)。

  3. 然后,测试运行器通过 HTTP 调用未修改的应用程序(2)。

  4. 然后,应用程序调用其他服务,如 Redis 和数据库 - 就像通常一样。

然而,有一个需要注意的问题,它具有重大影响:端到端测试需要完全控制数据库才能可靠地运行。由于我们不希望在每次运行测试时清除我们的开发数据库,因此我们需要使用两个数据库:一个用于测试,另一个用于开发。

此外,端到端测试需要通过 HTTP 请求到达连接到 测试环境 的系统。这意味着我们还需要两个网络服务器端口:一个用于开发,一个用于测试上下文。

此设置有些复杂;因此以下图像有助于说明在开发时间和生产/CI 期间不同上下文之间的交互

                                                                                                                
                                                                                                                
                               Main Development Web                                              Behat CLI      
                               Server (usually port         Web Server used by                  (bin/behat)     
                                      8080)                Behat Tests (usually                        │        
                                                                Port 9090)                             │        
                                         │                                                             │        
                                         │                           ┌────────────────┐                │        
                                         │                           │                │                │        
                                         │                           ▼                │                ▼        
                                         │       ╔═════════════════════════╗        ╔══════════════════════════╗
    ######  ####### #     #              │       ║Development/Docker/Behat ║        ║  Testing/Behat Context   ║
    #     # #       #     #              │       ║         Context         ║        ║                          ║
    #     # #       #     #              │       ║                         ║        ║ behat tests executed as  ║
    #     # #####   #     #              │       ║   only overrides the    ║        ║ this context; so config  ║
    #     # #        #   #               │       ║      database name      ║        ║       should match       ║
    #     # #         # #                │       ╚═════════════════════════╝        ║ Development/Docker/Behat ║
    ######  #######    #                 │                                          ║                          ║
                                         ▼                                          ║                          ║
                                        ╔══════════════════════════════════╗        ║                          ║
                                        ║    Development/Docker Context    ║        ║                          ║
                                        ║                                  ║        ║                          ║
                                        ║ contains the main configuration  ║        ║                          ║
                                        ║             for DEV              ║        ║                          ║
                                        ╚══════════════════════════════════╝        ╚══════════════════════════╝
                                                                                                                
                                                                                                                
                                                                                                                
                                                                                                                
                                                                                                                
                                                                                                                
                                                                                                                
                                                                                                                
                                                                                                                
                               Main Production Web                                              Behat CLI      
                               Server (usually port         Web Server used by                  (bin/behat)     
                                      8080)                Behat Tests (usually                        │        
                                                                Port 9090)                             │        
                                         │                                                             │        
                                         │                           ┌────────────────┐                │        
                                         │                           │                │                │        
          #####  ###                     │                           ▼                │                ▼        
         #     #  #                      │       ╔═════════════════════════╗        ╔══════════════════════════╗
         #        #                      │       ║Production/Kubernetes/Beh║        ║  Testing/Behat Context   ║
         #        #                      │       ║       at Context        ║        ║                          ║
         #        #                      │       ║                         ║        ║ behat tests executed as  ║
         #     #  #                      │       ║   only overrides the    ║        ║ this context; so config  ║
          #####  ###                     │       ║      database name      ║        ║       should match       ║
                                         │       ╚═════════════════════════╝        ║Development/Kubernetes/Beh║
                                         │                                          ║            at            ║
                                         ▼                                          ║                          ║
                                        ╔══════════════════════════════════╗        ║                          ║
                                        ║  Development/Kubernetes Context  ║        ║                          ║
                                        ║                                  ║        ║                          ║
                                        ║ contains the main configuration  ║        ║                          ║
                                        ║             for PROD             ║        ║                          ║
                                        ╚══════════════════════════════════╝        ╚══════════════════════════╝

安装和设置说明

对于希望将 BDD 集成到项目中的人来说,这是必读的。

composer require sandstorm/e2etesttools @dev
./flow behat:setup
./flow behat:kickstart Your.SitePackageKey http://127.0.0.1:8081
rm bin/selenium-server.jar # we do not need this
  • 您可以删除 behat.yml 并只保留 behat.yml.dist

  • behat.yml.dist 中,完全删除 Behat\MinkExtension 部分。

    Mink 是一个通用的 "浏览器控制器 API",根据我们的经验,它使用起来有些脆弱,并增加了不必要的复杂性。我们建议直接使用 Playwright。

  • 您应该配置 Flow/Neos 的 Configuration/Testing/Behat/Settings.yaml 并将生产 Settings.yaml 复制到其中;以确保 Behat 访问与生产应用程序相同的数据库。

  • 您应该创建一个 Configuration/Development/Docker/Behat/Settings.yaml,其内容如下

  Neos:
    Flow:
      persistence:
        backendOptions:
          dbname: '%env:DB_NEOS_DATABASE_E2ETEST%'
  • 您应该创建一个 Configuration/Production/Kubernetes/Behat/Settings.yaml,其内容如下
  Neos:
    Flow:
      persistence:
        backendOptions:
          dbname: '%env:DB_NEOS_DATABASE_E2ETEST%'

设置 Playwright

我们建议将此包中的Resources/Private/e2e-testrunner-template复制到Git仓库的根目录,并将文件夹命名为e2e-testrunner(在我们的项目中,通常位于Neos根目录的上一个级别)。

此外,您还需要以下.gitlab-ci.yml文件以进行构建

package_app:
  stage: build
  image: docker-hub.sandstorm.de/docker-infrastructure/php-app/build:7.4-v2
  interruptible: true
  script:
    - cd app
    # NOTE: for E2E tests we HAVE also to install DEV dependencies; otherwise we won't be able to run behavioral tests then.
    - COMPOSER_CACHE_DIR=.composer-cache composer install --dev --ignore-platform-reqs
    - cd ..

    # set up Behat
    - mkdir -p app/Build && cp -R app/Packages/Application/Neos.Behat/Resources/Private/Build/Behat app/Build/Behat
    - cd app/Build/Behat && COMPOSER_CACHE_DIR=../../.composer-cache composer install && cd ../../../

    # build image
    - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY
    - docker build -t $CI_REGISTRY_IMAGE:$CI_BUILD_REF_SLUG .
    - docker push $CI_REGISTRY_IMAGE:$CI_BUILD_REF_SLUG
  tags:
    - docker
    - privileged
  cache:
    key: PROJECTNAME__composer
    paths:
      - app/.composer-cache



build_e2e_testrunner:
  stage: build
  image: docker-hub.sandstorm.de/docker-infrastructure/php-app/build:7.4-v2
  interruptible: true
  script:
    - cd e2e-testrunner
    - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY
    - docker build -t $CI_REGISTRY_IMAGE:$CI_BUILD_REF_SLUG-e2e-testrunner .
    - docker push $CI_REGISTRY_IMAGE:$CI_BUILD_REF_SLUG-e2e-testrunner
    - cd ..
  tags:
    - docker
    - privileged

然后,为了运行测试,您需要在.gitlab-ci.yml中添加类似以下片段。

每个相关服务(如redis、数据库等)都需要使用services条目启动。确保服务的Docker镜像版本与docker-compose.yml中的开发和生产镜像相匹配。

作业的环境变量将传递给所有服务 - 因此,所有连接的服务和主作业共享相同的环境变量。因此,您需要将SUT(即主作业)和所有相关服务的环境变量添加到测试作业的variables部分。

e2e_test:
  stage: test
  interruptible: true
  # we're running this job inside the production image we've just built previously
  image:
    name: $CI_REGISTRY_IMAGE:$CI_BUILD_REF_SLUG
    # we may need to override the entrypoint here
    entrypoint: [ "" ]
  dependencies: [ ] # we do not need any artifacts from prior steps
  variables:
    # service mariadb
    MYSQL_USER: 'ci_user'
    MYSQL_PASSWORD: 'ci_db_password'
    MYSQL_DATABASE: 'ci_test'

    # System under Test
    FLOW_CONTEXT: 'Production/Kubernetes'
    DB_NEOS_HOST: 'mariadb'
    DB_NEOS_PORT: '3306'
    DB_NEOS_USER: '${MYSQL_USER}'
    DB_NEOS_PASSWORD: '${MYSQL_PASSWORD}'
    DB_NEOS_DATABASE: '${MYSQL_DATABASE}'
  services:
    - name: mariadb:10.5
    # here, we make the e2e-testrunner available
    - name: $CI_REGISTRY_IMAGE:$CI_BUILD_REF_SLUG-e2e-testrunner
      alias: e2e-testrunner
  script:
    # ADJUST: the following lines must be adjusted to match the *entrypoint*
    - cd /app && ./flow doctrine:migrate
    # make E2E Test Server available (port 9090)
    - ln -s /etc/nginx/nginx-e2etest-server-prod.conf /etc/nginx/conf.d/nginx-e2etest-server-prod.conf

    - /bin/sh /start.sh &
    # the playwright API URL does not need to be adjusted as long as the service alias for playwright is `e2e-testrunner`.
    - export PLAYWRIGHT_API_URL=http://e2e-testrunner:3000

    # ADJUST: you might need to adjust the SUT URL; and the wait URL below
    - export SYSTEM_UNDER_TEST_URL_FOR_PLAYWRIGHT=http://$(hostname -i):9090
    - |
      # now wait until system under test is up and running
      until $(curl --output /dev/null --silent --head --fail http://127.0.0.1:9090); do
          printf '.'
          sleep 5
      done

    # actually run the tests
    # ADJUST: use your pacakge key here
    - cd /app && rm -Rf e2e-results && mkdir e2e-results && bin/behat     --format junit --out e2e-results       --format pretty --out std       -c Packages/Application/PACKAGEKEY/Tests/Behavior/behat.yml.dist
    - cp -R /app/e2e-results $CI_PROJECT_DIR/e2e-results
    - cp -R /app/Web/styleguide $CI_PROJECT_DIR/styleguide
  artifacts:
    expire_in: 4 weeks
    paths:
      - e2e-results
      - styleguide
    reports:
      junit: e2e-results/behat.xml

创建 FeatureContext

FeatureContext是包含Behat场景步骤定义的PHP类。我们提供了您应用于各种功能的基本特质。FeatureContext的骨架应如下所示

<?php

use Behat\Behat\Context\Context;
use Neos\Behat\Tests\Behat\FlowContextTrait;
use Neos\ContentRepository\Tests\Behavior\Features\Bootstrap\NodeOperationsTrait;
use Neos\Flow\ObjectManagement\ObjectManagerInterface;
use Neos\Flow\Tests\Behavior\Features\Bootstrap\SecurityOperationsTrait;
use Sandstorm\E2ETestTools\Tests\Behavior\Bootstrap\FusionRenderingTrait;
use Sandstorm\E2ETestTools\Tests\Behavior\Bootstrap\PlaywrightTrait;

require_once(__DIR__ . '/../../../../../../Packages/Application/Neos.Behat/Tests/Behat/FlowContextTrait.php');
require_once(__DIR__ . '/../../../../../../Packages/Application/Neos.ContentRepository/Tests/Behavior/Features/Bootstrap/NodeOperationsTrait.php');
require_once(__DIR__ . '/../../../../../../Packages/Framework/Neos.Flow/Tests/Behavior/Features/Bootstrap/SecurityOperationsTrait.php');
require_once(__DIR__ . '/../../../../../../Packages/Application/Sandstorm.E2ETestTools/Tests/Behavior/Bootstrap/FusionRenderingTrait.php');
require_once(__DIR__ . '/../../../../../../Packages/Application/Sandstorm.E2ETestTools/Tests/Behavior/Bootstrap/PlaywrightTrait.php');

class FeatureContext implements Context
{
    // This is for integration with Flow (so you have access to $this->objectManager of Flow).  (part of Neos.Behat)
    use FlowContextTrait;
    
    // prerequisite of NodeOperationsTrait (part of Neos.Flow)
    use SecurityOperationsTrait;
    
    // create Nodes etc. in Behat tests (part of Neos.ContentRepository)
    use NodeOperationsTrait {
        // take overridden "iHaveTheFollowingNodes" from FusionRenderingTrait
        FusionRenderingTrait::iHaveTheFollowingNodes insteadof NodeOperationsTrait;
    }
    
    // Render Fusion code and Styleguide (part of Sandstorm.E2ETestTools)
    use FusionRenderingTrait;
    
    // Browser Automation
    use PlaywrightTrait;

    /**
     * @var ObjectManagerInterface
     */
    protected $objectManager;

    public function __construct()
    {
        if (self::$bootstrap === null) {
            self::$bootstrap = $this->initializeFlow();
        }
        $this->objectManager = self::$bootstrap->getObjectManager();
        $this->setupSecurity();
        $this->setupPlaywright();
        
        // !!! You need to add the Site Package Key here, so that we are able to load the Fusion code properly.
        $this->setupFusionRendering('Site.Package.Key.Here');
        
        // !!! Important for usage with Neos: you need to publish resources that are created from fixtures
        $this->PersistentResourceTrait_registerResourcePersistedHook(function () {
            // publish resources post persist hook for PersistentResources created by fixtures
            // execute a: './flow resource:publish'
        });
    }

    /**
     * @return ObjectManagerInterface
     */
    public function getObjectManager(): ObjectManagerInterface
    {
        return $this->objectManager;
    }
}

加载 Styleguide 的 CSS 和 JavaScript

在您的Fusion代码中,将页面的JavaScript和CSS添加到Sandstorm.E2ETestTools:StyleguideStylesheetsSandstorm.E2ETestTools:StyleguideJavascripts原型中,例如以下方式

prototype(Sandstorm.E2ETestTools:StyleguideStylesheets) {
    headerAssets = PACKAGEKEY:Resources.HeaderAssets
}

此外,还需要正确配置基本URL。此包在Testing/Behat上下文中将其设置为"/",在大多数情况下会自动工作。

运行 Behat 测试

本部分是每个人必读的。我们建议将此部分复制到您项目的readme中。

首先,您需要在您的开发机上启动Playwright Server。为此,转到Git仓库中的e2e-testrunner,然后执行以下操作

npm install
node index.js
# now, the server is running on localhost:3000.
# Keep the server running as long as you want to execute Behavioral Tests. You can leave the server
# running for a very long time (e.g. a day).

其次,确保Docker容器正在运行;通常通过docker-compose build && docker-compose up -d。然后,进入neos容器:docker-compose exec neos /bin/bash,在容器内运行以下命令

./flow behat:setup
bin/behat -c Packages/Sites/[SITEPACKAGE_NAME]/Tests/Behavior/behat.yml.dist

Behat还支持运行单个测试或单个文件 - 它们需要在配置文件之后指定,例如

# run all scenarios in a given folder
bin/behat -c Packages/Sites/[SITEPACKAGE_NAME]/Tests/Behavior/behat.yml.dist Packages/Sites/[SITEPACKAGE_NAME]/Tests/Behavior/Features/Fusion/

# run all scenarios in the single feature file
bin/behat -c Packages/Sites/[SITEPACKAGE_NAME]/Tests/Behavior/behat.yml.dist Packages/Sites/[SITEPACKAGE_NAME]/Tests/Behavior/Features/WebsiteRendering.feature

# run the scenario starting at line 27
bin/behat -c Packages/Sites/[SITEPACKAGE_NAME]/Tests/Behavior/behat.yml.dist Packages/Sites/[SITEPACKAGE_NAME]/Tests/Behavior/Features/WebsiteRendering.feature:27

如果出现异常,使用--stop-on-failure运行测试可能很有帮助,这将在第一个错误处停止测试用例。然后,您可以检查测试数据库并手动重现错误。

此外,-vvv是一个有用的CLI标志(额外详细) - 它在出现错误时显示完整的异常堆栈跟踪。

关于如何编写Behat测试的提示,我们建议阅读Sandstorm.E2ETestTools README

风格指南

如果您使用样式指南功能(例如Then I store the Fusion output in the styleguide as "Button_Component_Basic"),则测试需要用@playwright进行注解,并且Playwright开发服务器需要正在运行。

然后,您可以通过127.0.0.1:8080/styleguide/访问样式指南。样式指南包含HTML快照和HTML的渲染图像。

编写 Behat 测试

在这里,我们尝试提供常见Behat场景的示例,以便您可以轻松开始。

Fusion 组件测试用例

您可以使用以下测试用例来测试组件 - 类似于您通常使用Monocle所做的。

一些提示

  • 我们需要设置一个最小的节点树,否则我们无法渲染链接。
@fixtures
@playwright
Feature: Testcase for Button Component

    Background:
        Given I have a site for Site Node "site"
        Given I have the following nodes:
            | Identifier                           | Path               | Node Type                | Properties                   | Language |
            | 5cb3a5f7-b501-40b2-b5a8-9de169ef1105 | /sites             | unstructured             | {}                           | de       |
            | 5e312d5b-9559-4bd2-8251-0182e11b4950 | /sites/site        | PACKAGEKEY:Document.Page | {}                           | de       |
            | 9cbaa2e2-d779-4936-aa02-0dab324da93e | /sites/site/nested | PACKAGEKEY:Document.Page | {"uriPathSegment": "nested"} | de       |


        Given I get a node by path "/sites/site" with the following context:
            | Workspace | Dimension: language |
            | live      | de                  |


    Scenario: Basic Button (external link)
        When I render the Fusion object "/testcase" with the current context node:
    """
    testcase = PACKAGEKEY:Component.Button {
      text = "External Link"
      link = "https://spiegel.de"
      isExternalLink = true
    }
    """
        Then in the fusion output, the inner HTML of CSS selector "a" matches "External Link"
        Then in the fusion output, the attributes of CSS selector "a" are:
            | Key    | Value              |
            | class  | button             |
            | href   | https://spiegel.de |
            | target | _blank             |
        Then I store the Fusion output in the styleguide as "Button_Component_Basic"

Fusion 集成测试用例

特别有价值的是,不仅要测试Fusion组件(这或多或少像是一个纯函数),而是测试给定的节点以某种方式渲染 - 这样就可以正确设置节点与Fusion组件之间的连接

一个测试用例可以像以下这样

@fixtures
@playwright
Feature: Testcase for Button Integration

    Background:
        Given I have a site for Site Node "site"
        Given I have the following nodes:
            | Identifier                           | Path               | Node Type                | Properties                   | Language |
            | 5cb3a5f7-b501-40b2-b5a8-9de169ef1105 | /sites             | unstructured             | {}                           | de       |
            | 5e312d5b-9559-4bd2-8251-0182e11b4950 | /sites/site        | PACKAGEKEY:Document.Page | {}                           | de       |
            | 9cbaa2e2-d779-4936-aa02-0dab324da93e | /sites/site/nested | PACKAGEKEY:Document.Page | {"uriPathSegment": "nested"} | de       |


    Scenario: Secondary Button
        Given I create the following nodes:
            | Path                      | Node Type                 | Properties                                                                   | Language |
            | /sites/site/main/testnode | PACKAGEKEY:Content.Button | {"type": "secondary", "link": "node://9cbaa2e2-d779-4936-aa02-0dab324da93e"} | de       |
        Given I get a node by path "/sites/site/main/testnode" with the following context:
            | Workspace | Dimension: language |
            | live      | de                  |

        When I render the Fusion object "/testcase" with the current context node:
    """
    testcase = PACKAGEKEY:Content.Button
    """
        Then in the fusion output, the attributes of CSS selector "a" are:
            | Key  | Value      |
            | href | /de/nested |

        Then I store the Fusion output in the styleguide as "Button_Integration_Secondary"

全页快照测试用例

这个测试用例测试的是完整页面的渲染,而不仅仅是单个组件。它主要用于视觉检查;而且,你很可能不会使用特定的断言。

在这种情况下,渲染依赖于更多的节点,因此设置包含所有相关节点的behat fixture可能有点繁琐。幸运的是,这个包中有一些助手可以帮助这个过程。我们建议编写一个像下面的CommandController

<?php

namespace PACKAGEKEY\Command;

use Neos\ContentRepository\Domain\Model\NodeInterface;
use Neos\ContentRepository\Domain\Service\ContextFactoryInterface;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Cli\CommandController;
use Sandstorm\E2ETestTools\StepGenerator\NodeTableBuilderService;

class StepGeneratorCommandController extends CommandController
{
    /**
     * @Flow\Inject
     */
    protected ContextFactoryInterface $contextFactory;

    /**
     * Main API for creating NodeTable instances to print BDD steps.
     *
     * @Flow\Inject
     */
    protected NodeTableBuilderService $nodeTableBuilderService;

    public function homepageCommand()
    {
        $nodeTable = $this->nodeTableBuilderService->nodeTable()
            ->withDefaultNodeProperties(['Language' => 'de'])
            ->build();
        $siteNode = $this->getSiteNode();

        $nodeTable->addParents($siteNode);
        $nodeTable->addNode($siteNode);
        $nodeTable->addNodesUnderneathExcludingAutoGeneratedChildNodes($siteNode, '!Neos.Neos:Document'); // we recurse into the content of the homepage
        $nodeTable->addNodesUnderneathExcludingAutoGeneratedChildNodes($siteNode, 'Neos.Neos:Document'); // we render the remaining document nodes so we can have a menu rendered (but without content)

        $nodeTable->print();
    }

    /**
     * @return NodeInterface
     */
    public function getSiteNode(): NodeInterface
    {
        $context = $this->contextFactory->create([
            'workspaceName' => 'live',
            'invisibleContentShown' => true,
            'dimensions' => [
                'language' => ['de']
            ],
            'targetDimensions' => [
                'language' => 'de'
            ]
        ]);
        return $context->getCurrentSiteNode();
    }
}

现在,当你运行./flow stepGenerator:homepage时,你会得到一个如下所示的表格

Given I have the following nodes:
    | Path   | Node Type    | Properties | HiddenInIndex | Language |
    | /sites | unstructured | []         | false         | de       |
    # ... many more nodes here in this table ...

这可以粘贴到如下所示的测试用例中

@fixtures
@playwright
Feature: Homepage Rendering

    Scenario: Full Homepage Rendering
        Given I have a site for Site Node "site"
    # to regenerate, use: ./flow stepGenerator:homepage
        Given I have the following nodes:
            | Path   | Node Type    | Properties | HiddenInIndex | Language |
            | /sites | unstructured | []         | false         | de       |
    # ... many more nodes here ...

        Given I get a node by path "/sites/site" with the following context:
            | Workspace | Dimension: language |
            | live      | de                  |

        Given I accepted the Cookie Consent
        When I render the page
        Then I store the Fusion output in the styleguide as "Page_Homepage"
        Then I store the Fusion output in the styleguide as "Page_Homepage_Mobile" using viewport width "320"

这可以生成不同页面的**响应式、可复制的截图**,并且当占位符数据发生变化时能够重新生成。

BDD测试中的持久资源

如果你的节点fixture指向Neos.Media模块中的某些资产,你也可以为它们生成fixture。创建NodeTable时需要传递第二个参数($fixtureBasePath)。

你可能希望将你的资产fixture存储在功能文件附近。

TODO 解释如何设置fixture基础路径

    // ... Step Generator Command Controller 

    public function homepageCommand()
    {
        $nodeTable = $this->nodeTableBuilderService->nodeTable()
            ->withDefaultNodeProperties(['Language' => 'de'])
            // !!! Here you setup your directory for storing your fixture files.
            // It will print a path relative to the Flow package directory.
            //  -> most likely: Sites/Your.PackageKey/Tests/Behavior/Features/Homepage/Resources/someSHA1.png (depending on the type of the composer package)
            ->withFixtureBasePath('Your.PackageKey', 'Tests/Behavior/Features/Homepage/Resources/')
            ->build();
        $siteNode = $this->getSiteNode();

        $nodeTable->addParents($siteNode);
        $nodeTable->addNode($siteNode);
        $nodeTable->addNodesUnderneathExcludingAutoGeneratedChildNodes($siteNode, '!Neos.Neos:Document'); // we recurse into the content of the homepage
        $nodeTable->addNodesUnderneathExcludingAutoGeneratedChildNodes($siteNode, 'Neos.Neos:Document'); // we render the remaining document nodes so we can have a menu rendered (but without content)

        // when the table is printed, it includes other tables containing asset fixtures
        $nodeTable->print();
    }
    
    // ...

假设你的节点数据fixture中有三张图片(节点属性类型为ImageInterface)。你的输出可能看起来像

Given I have the following images:
    | Image ID                             | Width | Height | Filename            | Collection | Relative Publication Path | Path                                                                                                        |
    | 3a28c97c-58f1-45c5-b1ad-2f491c904467 |       |        | Map-circle-blue.svg | persistent |                           | Sites/Your.Package/Tests/Behavior/Features/Homepage/Resources/9600acebed149b1e0178b214a7f3a82bc7a829a4.svg  |
    | 846d085f-091b-4d08-82bb-e5f04150c594 | 615   | 418    | cat_caviar.jpeg     | persistent |                           | Sites/Your.Package/Tests/Behavior/Features/Homepage/Resources/ee53c207588c199b4e5359f5e06d241b0d93b78e.jpeg |
    | 3ca6e806-182a-4af2-9a60-50d2ff0bcbdb | 4500  | 4500   | mark-man-stock.png  | persistent |                           | Sites/Your.Package/Tests/Behavior/Features/Homepage/Resources/9784f58d2f6810b773807b3cfd56dcbe2b3a1c65.png  |
Given I have the following nodes:
    | Path | Node Type | Properties | HiddenInIndex | Language |
    # ... nodes go here here with reference to Image ID in their serialized properties
    # a property might look like: { ..., "myImageProperty":{"__flow_object_type":"Neos\\Media\\Domain\\Model\\Image","__identifier":"3a28c97c-58f1-45c5-b1ad-2f491c904467"}, ...

注意,Path列的值是相对于Flow包目录打印和读取的。这应该使你的测试更加或更少地与环境独立。通常,这些文件存储在DistributionPackages/*包中,该包是链接到Flow包目录的(因此可以从你的测试中读取,并从你的命令控制器中进行写入)。此外,这些文件应该添加到git中,因为它们是测试用例的一部分。

通过步骤动态修改SUT URL

默认情况下,SUT URL是通过环境变量静态配置的。在某些情况下,这并不足够。

用例

基于主机信息自定义内容维度解析

假设,你的Neos项目有一个自定义内容维度值解析器,例如,通过主机名或子域。SUT基本URL是通过环境变量静态配置的。但在提到特殊情况时,你需要通过你自己的自定义步骤修改动态基本URL。

多站设置

当你的Neos应用程序有多个站点时,主机名也需要通过自定义步骤定义。

PlaywrightConnector为此目的提供了一个API

公开API:PlaywrightTrait#setSystemUnderTestUrlModifier(\Closure $urlModifier): void委托给内部:PlaywrightConnector#setSystemUnderTestUrlModifier(\Closure $urlModifier): void

注意,修改器在每个场景后都会重置。

你需要从你的自定义步骤调用该setter,自定义步骤可能看起来像

...

    /**
     * @Given my base URL is :baseUrl
     */
    public function myBaseUrlIs($baseUrl)
    {
        $this->setSystemUnderTestUrlModifier(function (string $staticBaseUrl) use ($baseUrl) {
            return $baseUrl;
        });
    }

    /**
     * @Given my subdomain is :subdomain
     */
    public function mySubdomainIs($subdomain)
    {
        $this->setSystemUnderTestUrlModifier(function (string $baseUrl) use ($subdomain) {
            return sprintf("%s://%s.%s.nip.io:%s/%s",
                parse_url($baseUrl, PHP_URL_SCHEME),
                $subdomain,
                parse_url($baseUrl, PHP_URL_HOST),
                parse_url($baseUrl, PHP_URL_PORT),
                parse_url($baseUrl, PHP_URL_PATH),
            );
        });
    }

...    

和behat调用

Given my subdomain is "de"

用于使用Sandstorm.NeosAcl的Site Packages的使用方法

将此添加到你的Testing/Behat上下文中的Policy.yaml中

roles:
  # this is necessary to allow the test runner to create fixtures when neos
  # acl package is installed
  'Neos.Flow:Everybody':
      privileges:
        -
          privilegeTarget: 'Sandstorm.NeosAcl:EditAllNodes'
          permission: GRANT
        -
          privilegeTarget: 'Sandstorm.NeosAcl:CreateAllNodes'
          permission: GRANT
        -
          privilegeTarget: 'Sandstorm.NeosAcl:RemoveAllNodes'
          permission: GRANT