[TASK] Acceptance tests for keyboard interaction with pagetree 21/62521/5
authorMichael Telgkamp <michael.telgkamp@mindscreen.de>
Tue, 22 Oct 2019 20:20:27 +0000 (22:20 +0200)
committerBenni Mack <benni@typo3.org>
Fri, 27 Dec 2019 14:03:11 +0000 (15:03 +0100)
Add keyboard interaction acceptance tests for the pagetree interactions.

Currently testing Home key, End key, navigation with Up and Down keys,
opening a selected entry with Enter and collapsing and expanding of
subtrees with Left / Right keys.

Resolves: #89832
Resolves: #89955
Releases: master
Change-Id: Ibe3c83fe6142296e333a66e68d67e283e2000957
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/62521
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Benni Mack <benni@typo3.org>
Build/Scripts/runTests.sh
Build/bamboo/src/main/java/core/AbstractCoreSpec.java
Build/bamboo/src/main/java/core/AbstractPreMergeSpec.java
Build/bamboo/src/main/java/core/NightlySpec.java
Build/testing-docker/local/docker-compose.yml
typo3/sysext/core/Tests/Acceptance/Fixtures/pages.xml [new file with mode: 0644]
typo3/sysext/core/Tests/Acceptance/PageTree.suite.yml [new file with mode: 0644]
typo3/sysext/core/Tests/Acceptance/PageTree/KeyboardAccess/SelectPagetreeWithKeyboardCest.php [new file with mode: 0644]
typo3/sysext/core/Tests/Acceptance/Support/Extension/PageTreeCoreEnvironment.php [new file with mode: 0644]

index 2ac8251..a6c6c4d 100755 (executable)
@@ -64,6 +64,7 @@ Options:
     -s <...>
         Specifies which test suite to run
             - acceptance: backend acceptance tests
+            - acceptancePagetree: backend acceptance tests for page tree
             - buildCss: execute scss to css builder
             - buildJavascript: execute typescript to javascript builder
             - cglGit: test and fix latest committed patch for CGL compliance
@@ -282,6 +283,13 @@ case ${TEST_SUITE} in
         SUITE_EXIT_CODE=$?
         docker-compose down
         ;;
+    acceptancePagetree)
+        setUpDockerComposeDotEnv
+        docker-compose run prepare_acceptance_pagetree_mariadb10
+        docker-compose run acceptance_pagetree_mariadb10
+        SUITE_EXIT_CODE=$?
+        docker-compose down
+        ;;
     buildCss)
         setUpDockerComposeDotEnv
         docker-compose run build_css
index 336b5c9..e4dc972 100644 (file)
@@ -508,6 +508,66 @@ abstract class AbstractCoreSpec {
     }
 
     /**
+     * Jobs for mysql based acceptance tests
+     */
+    ArrayList<Job> getJobsAcceptanceTestsPageTreeMysql(int stageNumber, String requirementIdentifier, Task composerTask, Boolean isSecurity) {
+        String name = getTaskNamePartForComposer(stageNumber);
+        ArrayList<Job> jobs = new ArrayList<Job>();
+
+        jobs.add(new Job("Accept PageTree my " + name + " " + requirementIdentifier, new BambooKey("ACPTMY" + stageNumber + requirementIdentifier))
+            .description("Run acceptance tests for page tree" + requirementIdentifier)
+            .pluginConfigurations(this.getDefaultJobPluginConfiguration())
+            .tasks(
+                this.getTaskGitCloneRepository(),
+                this.getTaskGitCherryPick(isSecurity),
+                this.getTaskStopDanglingContainers(),
+                composerTask,
+                this.getTaskPrepareAcceptanceTest(),
+                this.getTaskDockerDependenciesAcceptanceBackendMariadb10(),
+                new ScriptTask()
+                    .description("Execute codeception acceptance test for pageTree.")
+                    .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
+                    .inlineBody(
+                        this.getScriptTaskBashInlineBody() +
+                            "function codecept() {\n" +
+                            "    docker run \\\n" +
+                            "        -u ${HOST_UID} \\\n" +
+                            "        -v /bamboo-data/${BAMBOO_COMPOSE_PROJECT_NAME}/passwd:/etc/passwd \\\n" +
+                            "        -v ${BAMBOO_COMPOSE_PROJECT_NAME}_bamboo-data:/srv/bamboo/xml-data/build-dir/ \\\n" +
+                            "        -e typo3DatabaseName=func_test \\\n" +
+                            "        -e typo3DatabaseUsername=root \\\n" +
+                            "        -e typo3DatabasePassword=funcp  \\\n" +
+                            "        -e typo3DatabaseHost=mariadb10  \\\n" +
+                            "        --name ${BAMBOO_COMPOSE_PROJECT_NAME}sib_adhoc \\\n" +
+                            "        --network ${BAMBOO_COMPOSE_PROJECT_NAME}_test \\\n" +
+                            "        --rm \\\n" +
+                            "        typo3gmbh/" + requirementIdentifier.toLowerCase() + ":latest \\\n" +
+                            "        bin/bash -c \"cd ${PWD}; ./bin/codecept $*\"\n" +
+                            "}\n" +
+                            "\n" +
+                            "codecept run PageTree -d -c typo3/sysext/core/Tests/codeception.yml --xml reports.xml --html reports.html\n"
+                    )
+            )
+            .finalTasks(
+                this.getTaskStopDockerDependencies(),
+                new TestParserTask(TestParserTaskProperties.TestType.JUNIT)
+                    .resultDirectories("typo3temp/var/tests/AcceptanceReports/reports.xml")
+            )
+            .artifacts(new Artifact()
+                .name("Test Report")
+                .copyPattern("typo3temp/var/tests/AcceptanceReports/")
+                .shared(false)
+            )
+            .requirements(
+                this.getRequirementDocker10()
+            )
+            .cleanWorkingDirectory(true)
+        );
+
+        return jobs;
+    }
+
+    /**
      * Jobs for mysql based functional tests with driver mysqli
      */
     ArrayList<Job> getJobsFunctionalTestsMysqlWithDriverMySqli(int stageNumber, int numberOfChunks, String requirementIdentifier, Task composerTask, Boolean isSecurity) {
index a50f053..c40cc4a 100644 (file)
@@ -54,6 +54,7 @@ abstract class AbstractPreMergeSpec extends AbstractCoreSpec {
         jobsMainStage.add(this.getJobAcceptanceTestInstallSqlite(0, phpVersions[0], this.getTaskComposerInstall(phpVersions[0]), isSecurity));
 
         jobsMainStage.addAll(this.getJobsAcceptanceTestsBackendMysql(0, numberOfAcceptanceTestJobs, phpVersions[1], this.getTaskComposerInstall(phpVersions[1]), isSecurity));
+        jobsMainStage.addAll(this.getJobsAcceptanceTestsPageTreeMysql(0, phpVersions[1], this.getTaskComposerInstall(phpVersions[1]), isSecurity));
 
         jobsMainStage.add(this.getJobIntegrationDocBlocks(phpVersions[0], this.getTaskComposerInstall(phpVersions[0]), isSecurity));
         jobsMainStage.add(this.getJobIntegrationAnnotations(phpVersions[0], this.getTaskComposerInstall(phpVersions[0]), isSecurity));
index 5170b18..781d2d5 100644 (file)
@@ -235,6 +235,7 @@ public class NightlySpec extends AbstractCoreSpec {
                 Task composerTask = getComposerTaskByStageNumber(phpVersion, stageNumber);
                 jobs.add(this.getJobAcceptanceTestInstallMysql(stageNumber, phpVersion, composerTask, false));
                 jobs.addAll(this.getJobsAcceptanceTestsBackendMysql(stageNumber, numberOfAcceptanceTestJobs, phpVersion, composerTask, false));
+                jobs.addAll(this.getJobsAcceptanceTestsPageTreeMysql(stageNumber, phpVersion, composerTask, false));
             }
         }
         return jobs;
index 4e39c7c..a401c67 100644 (file)
@@ -100,6 +100,46 @@ services:
           && ./bin/codecept run Backend -d -c typo3/sysext/core/Tests/codeception.yml ${TEST_FILE} --html reports.html
       "
 
+  prepare_acceptance_pagetree_mariadb10:
+    image: alpine:3.8
+    links:
+      - mariadb10
+      - chrome
+      - web
+    command: >
+      /bin/sh -c "
+        if [ ${SCRIPT_VERBOSE} -eq 1 ]; then
+          set -x
+        fi
+        echo Waiting for database start...;
+        while ! nc -z mariadb10 3306; do
+          sleep 1;
+        done;
+        echo Database is up;
+      "
+  acceptance_pagetree_mariadb10:
+    image: typo3gmbh/${DOCKER_PHP_IMAGE}:latest
+    user: ${HOST_UID}
+    environment:
+      typo3DatabaseName: func_test
+      typo3DatabaseUsername: root
+      typo3DatabasePassword: funcp
+      typo3DatabaseHost: mariadb10
+    volumes:
+      - ${CORE_ROOT}:${CORE_ROOT}
+      - ${HOST_HOME}:${HOST_HOME}
+      - /etc/passwd:/etc/passwd:ro
+      - /etc/group:/etc/group:ro
+    working_dir: ${CORE_ROOT}
+    command: >
+      /bin/sh -c "
+        if [ ${SCRIPT_VERBOSE} -eq 1 ]; then
+          set -x
+        fi
+        mkdir -p typo3temp/var/tests/ \
+          && ./bin/codecept run PageTree -d -c typo3/sysext/core/Tests/codeception.yml ${TEST_FILE} --html reports.html
+      "
+
   prepare_acceptance_install_mariadb10:
     image: alpine:3.8
     links:
diff --git a/typo3/sysext/core/Tests/Acceptance/Fixtures/pages.xml b/typo3/sysext/core/Tests/Acceptance/Fixtures/pages.xml
new file mode 100644 (file)
index 0000000..1d7bc91
--- /dev/null
@@ -0,0 +1,404 @@
+<?xml version="1.0" encoding="utf-8"?>
+<dataset>
+    <pages>
+        <uid>1</uid>
+        <pid>0</pid>
+        <title>Root</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <is_siteroot>1</is_siteroot>
+        <perms_everybody>15</perms_everybody>
+    </pages>
+    <pages>
+        <uid>2</uid>
+        <pid>1</pid>
+        <title>Dummy 1-2</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>15</perms_everybody>
+    </pages>
+    <pages>
+        <uid>3</uid>
+        <pid>1</pid>
+        <title>Dummy 1-3</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>15</perms_everybody>
+    </pages>
+    <pages>
+        <uid>4</uid>
+        <pid>1</pid>
+        <title>Dummy 1-4</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>15</perms_everybody>
+    </pages>
+    <pages>
+        <uid>5</uid>
+        <pid>4</pid>
+        <title>Dummy 1-4-5</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>15</perms_everybody>
+    </pages>
+    <pages>
+        <uid>6</uid>
+        <pid>4</pid>
+        <title>Dummy 6</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>15</perms_everybody>
+    </pages>
+    <pages>
+        <uid>7</uid>
+        <pid>1</pid>
+        <title>Dummy 1-7</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>8</uid>
+        <pid>1</pid>
+        <title>Dummy 1-8</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>9</uid>
+        <pid>1</pid>
+        <title>Dummy 1-9</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>10</uid>
+        <pid>1</pid>
+        <title>Dummy 1-10</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>11</uid>
+        <pid>10</pid>
+        <title>Dummy 1-10-11</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>12</uid>
+        <pid>10</pid>
+        <title>Dummy 1-10-12</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>13</uid>
+        <pid>10</pid>
+        <title>Dummy 1-10-13</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>14</uid>
+        <pid>1</pid>
+        <title>Dummy 1-14</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>15</uid>
+        <pid>1</pid>
+        <title>Dummy 1-15</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>16</uid>
+        <pid>1</pid>
+        <title>Dummy 1-16</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>17</uid>
+        <pid>1</pid>
+        <title>Dummy 1-17</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>18</uid>
+        <pid>1</pid>
+        <title>Dummy 1-18</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>19</uid>
+        <pid>1</pid>
+        <title>Dummy 1-19</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>20</uid>
+        <pid>1</pid>
+        <title>Dummy 1-20</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>21</uid>
+        <pid>1</pid>
+        <title>Dummy 1-21</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>22</uid>
+        <pid>1</pid>
+        <title>Dummy 1-22</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>23</uid>
+        <pid>1</pid>
+        <title>Dummy 1-23</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>24</uid>
+        <pid>1</pid>
+        <title>Dummy 1-24</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>25</uid>
+        <pid>1</pid>
+        <title>Dummy 1-25</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>26</uid>
+        <pid>1</pid>
+        <title>Dummy 1-26</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>27</uid>
+        <pid>1</pid>
+        <title>Dummy 1-27</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>28</uid>
+        <pid>1</pid>
+        <title>Dummy 1-28</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>29</uid>
+        <pid>1</pid>
+        <title>Dummy 1-29</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>30</uid>
+        <pid>1</pid>
+        <title>Dummy 1-30</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>31</uid>
+        <pid>1</pid>
+        <title>Dummy 1-31</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>32</uid>
+        <pid>1</pid>
+        <title>Dummy 1-32</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>33</uid>
+        <pid>1</pid>
+        <title>Dummy 1-33</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>34</uid>
+        <pid>1</pid>
+        <title>Dummy 1-34</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>35</uid>
+        <pid>1</pid>
+        <title>Dummy 1-35</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>36</uid>
+        <pid>1</pid>
+        <title>Dummy 1-36</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>37</uid>
+        <pid>1</pid>
+        <title>Dummy 1-37</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>38</uid>
+        <pid>1</pid>
+        <title>Dummy 1-38</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>39</uid>
+        <pid>1</pid>
+        <title>Dummy 1-39</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>40</uid>
+        <pid>1</pid>
+        <title>Dummy 1-40</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>41</uid>
+        <pid>1</pid>
+        <title>Dummy 1-41</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>42</uid>
+        <pid>1</pid>
+        <title>Dummy 1-42</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>43</uid>
+        <pid>1</pid>
+        <title>Dummy 1-43</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>44</uid>
+        <pid>1</pid>
+        <title>Dummy 1-44</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>45</uid>
+        <pid>1</pid>
+        <title>Dummy 1-45</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>46</uid>
+        <pid>1</pid>
+        <title>Dummy 1-46</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>47</uid>
+        <pid>1</pid>
+        <title>Dummy 1-47</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>48</uid>
+        <pid>1</pid>
+        <title>Dummy 1-48</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>49</uid>
+        <pid>1</pid>
+        <title>Dummy 1-49</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+    <pages>
+        <uid>50</uid>
+        <pid>1</pid>
+        <title>Dummy 1-50</title>
+        <doktype>1</doktype>
+        <deleted>0</deleted>
+        <perms_everybody>0</perms_everybody>
+    </pages>
+</dataset>
diff --git a/typo3/sysext/core/Tests/Acceptance/PageTree.suite.yml b/typo3/sysext/core/Tests/Acceptance/PageTree.suite.yml
new file mode 100644 (file)
index 0000000..bccf17f
--- /dev/null
@@ -0,0 +1,22 @@
+class_name: BackendTester
+modules:
+  enabled:
+    - WebDriver:
+        url: http://web:8000/typo3temp/var/tests/acceptance
+        browser: chrome
+        wait: 1
+        host: chrome
+    - \TYPO3\TestingFramework\Core\Acceptance\Helper\Acceptance
+    - \TYPO3\TestingFramework\Core\Acceptance\Helper\Login:
+        sessions:
+            # This sessions must exist in the database fixture to get a logged in state.
+            editor: ff83dfd81e20b34c27d3e97771a4525a
+            admin: 886526ce72b86870739cc41991144ec1
+    - Asserts
+
+extensions:
+    enabled:
+        - TYPO3\CMS\Core\Tests\Acceptance\Support\Extension\PageTreeCoreEnvironment
+
+groups:
+  AcceptanceTests-Job-*: AcceptanceTests-Job-*
diff --git a/typo3/sysext/core/Tests/Acceptance/PageTree/KeyboardAccess/SelectPagetreeWithKeyboardCest.php b/typo3/sysext/core/Tests/Acceptance/PageTree/KeyboardAccess/SelectPagetreeWithKeyboardCest.php
new file mode 100644 (file)
index 0000000..dd904cd
--- /dev/null
@@ -0,0 +1,194 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Core\Tests\Acceptance\PageTree\KeyboardAccess;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Exception;
+use Facebook\WebDriver\WebDriverKeys;
+use TYPO3\CMS\Core\Tests\Acceptance\Support\BackendTester;
+use TYPO3\CMS\Core\Tests\Acceptance\Support\Helper\PageTree;
+
+/**
+ * Page and page tree related tests.
+ */
+class SelectPagetreeWithKeyboardCest
+{
+    /**
+     * Open list module of styleguide elements basic page
+     *
+     * @param BackendTester $I
+     * @param PageTree $pageTree
+     * @throws Exception
+     */
+    public function _before(BackendTester $I, PageTree $pageTree)
+    {
+        $I->useExistingSession('admin');
+        $I->click('List');
+        $pageTree->openPath(['Root']);
+        $I->waitForElement('#typo3-pagetree-tree .nodes .node', 5);
+    }
+
+    /**
+     * check selecting the next key in the page tree and open it using Enter
+     *
+     * @param BackendTester $I
+     */
+    public function focusPageWithDownKeyAndOpenItWithEnter(BackendTester $I)
+    {
+        $I->seeElement('#typo3-pagetree-tree [tabindex="0"]');
+        $I->pressKey('#typo3-pagetree-tree [tabindex="0"]', WebDriverKeys::DOWN);
+        $I->assertEquals(
+            'identifier-0_2',
+            $I->grabAttributeFrom('#typo3-pagetree-tree [tabindex="0"]', 'id')
+        );
+        $I->pressKey('#typo3-pagetree-tree [tabindex="0"]', WebDriverKeys::ENTER);
+        $I->switchToContentFrame();
+        $I->see('Dummy 1-2');
+    }
+
+    /**
+     * check selecting the next key in the page tree and open it using Enter
+     *
+     * @param BackendTester $I
+     */
+    public function focusPageWithDownAndUpKey(BackendTester $I)
+    {
+        $I->seeElement('#typo3-pagetree-tree [tabindex="0"]');
+        $I->pressKey('#typo3-pagetree-tree [tabindex="0"]', WebDriverKeys::DOWN);
+        $I->pressKey('#typo3-pagetree-tree [tabindex="0"]', WebDriverKeys::DOWN);
+        $I->assertEquals(
+            'identifier-0_3',
+            $I->grabAttributeFrom('#typo3-pagetree-tree [tabindex="0"]', 'id')
+        );
+        $I->pressKey('#typo3-pagetree-tree [tabindex="0"]', WebDriverKeys::UP);
+        $I->assertEquals(
+            'identifier-0_2',
+            $I->grabAttributeFrom('#typo3-pagetree-tree [tabindex="0"]', 'id')
+        );
+    }
+
+    /**
+     * Expand a subtree using keyboard keys
+     *
+     * @param BackendTester $I
+     */
+    public function expandSubtreeWithRightArrow(BackendTester $I)
+    {
+        $I->seeElement('#typo3-pagetree-tree [tabindex="0"]');
+        $I->amGoingTo('use keyboard to navigate through the tree');
+        for ($times = 0; $times < 3; $times++) {
+            $I->pressKey('#typo3-pagetree-tree [tabindex="0"]', WebDriverKeys::DOWN);
+        }
+        $I->amGoingTo('check if the parent key is selected and child is not visible');
+        $I->assertEquals(
+            'identifier-0_4',
+            $I->grabAttributeFrom('#typo3-pagetree-tree [tabindex="0"]', 'id')
+        );
+        $I->pressKey('#typo3-pagetree-tree [tabindex="0"]', WebDriverKeys::RIGHT);
+        $I->amGoingTo('check if parent is still selected and child is visible');
+        $I->assertEquals(
+            'identifier-0_4',
+            $I->grabAttributeFrom('#typo3-pagetree-tree [tabindex="0"]', 'id')
+        );
+        $I->seeElement('#identifier-0_5');
+        $I->pressKey('#typo3-pagetree-tree [tabindex="0"]', WebDriverKeys::RIGHT);
+        $I->amGoingTo('check if first childnode is selected');
+        $I->assertEquals(
+            'identifier-0_5',
+            $I->grabAttributeFrom('#typo3-pagetree-tree [tabindex="0"]', 'id')
+        );
+        $I->pressKey('#typo3-pagetree-tree [tabindex="0"]', WebDriverKeys::RIGHT);
+        $I->amGoingTo('check if first childnode is still selected');
+        $I->assertEquals(
+            'identifier-0_5',
+            $I->grabAttributeFrom('#typo3-pagetree-tree [tabindex="0"]', 'id')
+        );
+        $I->pressKey('#typo3-pagetree-tree [tabindex="0"]', WebDriverKeys::DOWN);
+        $I->amGoingTo('check if second childnode is still selected');
+        $I->assertEquals(
+            'identifier-0_6',
+            $I->grabAttributeFrom('#typo3-pagetree-tree [tabindex="0"]', 'id')
+        );
+    }
+
+    /**
+     * Expand a subtree using keyboard keys
+     *
+     * @param BackendTester $I
+     */
+    public function collapseSubtreeWithLeftArrow(BackendTester $I)
+    {
+        $I->seeElement('#typo3-pagetree-tree [tabindex="0"]');
+        $I->assertEquals(
+            'identifier-0_1',
+            $I->grabAttributeFrom('#typo3-pagetree-tree [tabindex="0"]', 'id')
+        );
+        $I->seeElement('#identifier-0_2');
+        $I->amGoingTo('collapse the current tree using left key');
+        $I->pressKey('#typo3-pagetree-tree [tabindex="0"]', WebDriverKeys::LEFT);
+        $I->assertEquals(
+            'identifier-0_1',
+            $I->grabAttributeFrom('#typo3-pagetree-tree [tabindex="0"]', 'id')
+        );
+        $I->cantSeeElement('#identifier-0_2');
+        $I->amGoingTo('go to parent of the current collapsed node using left key');
+        $I->pressKey('#typo3-pagetree-tree [tabindex="0"]', WebDriverKeys::LEFT);
+        $I->amGoingTo('check if parent (root) is selected and child is visible');
+        $I->assertEquals(
+            'identifier-0_0',
+            $I->grabAttributeFrom('#typo3-pagetree-tree [tabindex="0"]', 'id')
+        );
+        $I->canSeeElement('#identifier-0_1');
+    }
+
+    /**
+     * Check if the END key is working
+     *
+     * @param BackendTester $I
+     */
+    public function focusLastPageTreeItemWithEndKey(BackendTester $I)
+    {
+        $I->seeElement('#typo3-pagetree-tree [tabindex="0"]');
+        $I->pressKey('#typo3-pagetree-tree [tabindex="0"]', WebDriverKeys::END);
+        $I->assertEquals(
+            'identifier-0_50',
+            $I->grabAttributeFrom('#typo3-pagetree-tree [tabindex="0"]', 'id')
+        );
+    }
+
+    /**
+     * Check if the Home key is working
+     *
+     * @param BackendTester $I
+     */
+    public function focusFirstPageTreeItemWithHomeKey(BackendTester $I)
+    {
+        $I->seeElement('#typo3-pagetree-tree [tabindex="0"]');
+        for ($times = 0; $times < 15; $times++) {
+            $I->pressKey('#typo3-pagetree-tree [tabindex="0"]', WebDriverKeys::DOWN);
+        }
+        $I->assertEquals(
+            'identifier-0_21',
+            $I->grabAttributeFrom('#typo3-pagetree-tree [tabindex="0"]', 'id')
+        );
+
+        $I->pressKey('#typo3-pagetree-tree [tabindex="0"]', WebDriverKeys::HOME);
+        $I->assertEquals(
+            'identifier-0_0',
+            $I->grabAttributeFrom('#typo3-pagetree-tree [tabindex="0"]', 'id')
+        );
+    }
+}
diff --git a/typo3/sysext/core/Tests/Acceptance/Support/Extension/PageTreeCoreEnvironment.php b/typo3/sysext/core/Tests/Acceptance/Support/Extension/PageTreeCoreEnvironment.php
new file mode 100644 (file)
index 0000000..0451325
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Core\Tests\Acceptance\Support\Extension;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Codeception\Event\SuiteEvent;
+use Symfony\Component\Mailer\Transport\NullTransport;
+use TYPO3\CMS\Core\Core\Bootstrap;
+use TYPO3\TestingFramework\Core\Acceptance\Extension\BackendEnvironment;
+
+/**
+ * Load various core extensions and styleguide and call styleguide generator
+ */
+class PageTreeCoreEnvironment extends BackendEnvironment
+{
+    /**
+     * Set the list of core extensions and fixtures
+     *
+     * @var array
+     */
+    protected $localConfig = [
+        'coreExtensionsToLoad' => [
+            'core',
+            'beuser',
+            'extbase',
+            'fluid',
+            'filelist',
+            'extensionmanager',
+            'setup',
+            'backend',
+            'about',
+            'belog',
+            'install',
+            'frontend',
+            'recordlist',
+            'redirects',
+            'reports',
+            'sys_note',
+            'scheduler',
+            'tstemplate',
+        ],
+        'testExtensionsToLoad' => [],
+        'xmlDatabaseFixtures' => [
+            'typo3/sysext/core/Tests/Acceptance/Fixtures/pages.xml',
+            'PACKAGE:typo3/testing-framework/Resources/Core/Acceptance/Fixtures/be_users.xml',
+            'PACKAGE:typo3/testing-framework/Resources/Core/Acceptance/Fixtures/be_sessions.xml',
+            'PACKAGE:typo3/testing-framework/Resources/Core/Acceptance/Fixtures/be_groups.xml',
+            'PACKAGE:typo3/testing-framework/Resources/Core/Acceptance/Fixtures/sys_category.xml',
+        ],
+        'configurationToUseInTestInstance' => [
+            'MAIL' => [
+                'transport' => NullTransport::class
+            ]
+        ]
+    ];
+
+    /**
+     * Generate Page Tree data
+     *
+     * @param SuiteEvent $suiteEvent
+     */
+    public function bootstrapTypo3Environment(SuiteEvent $suiteEvent)
+    {
+        parent::bootstrapTypo3Environment($suiteEvent);
+        Bootstrap::initializeBackendUser();
+        $GLOBALS['BE_USER']->user['admin'] = 1;
+        $GLOBALS['BE_USER']->user['uid'] = 1;
+        $GLOBALS['BE_USER']->workspace = 0;
+        Bootstrap::initializeLanguageObject();
+    }
+}