[TASK] Functional tests for translated tt_content rendering in Extbase 58/53758/6
authorTymoteusz Motylewski <t.motylewski@gmail.com>
Wed, 23 Aug 2017 18:54:20 +0000 (20:54 +0200)
committerTymoteusz Motylewski <t.motylewski@gmail.com>
Mon, 28 Aug 2017 10:33:23 +0000 (12:33 +0200)
Introduce and Extbase version of the LocalizedContentRenderingTest.
It tests how language related TS settings influences content rendering.

Also changes exception code in ContentController, to make bamboo happy.

This test suite is documenting current behaviour, which is in fact
inconsistent with TypoScript tt_content rendering.

The next step is to provide a fix for extbase with a feature switch,
so this test suite will become a version with feature swich being disabled.

Resolves: #81823
Releases: master, 8.7, 7.6
Change-Id: Ia616e5089b0209cfb895216726f7192f39c88a45
Reviewed-on: https://review.typo3.org/53758
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Tymoteusz Motylewski <t.motylewski@gmail.com>
Tested-by: Tymoteusz Motylewski <t.motylewski@gmail.com>
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Controller/ContentController.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/TtContent.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Repository/TtContentRepository.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_localconf.php
typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_typoscript_setup.txt
typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/Frontend/ContentJsonRenderer.ts [new file with mode: 0644]
typo3/sysext/extbase/Tests/Functional/Persistence/TranslatedContentTest.php [new file with mode: 0644]

diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Controller/ContentController.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Controller/ContentController.php
new file mode 100644 (file)
index 0000000..5a2d356
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+namespace ExtbaseTeam\BlogExample\Controller;
+
+/*
+ * 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!
+ */
+
+/**
+ * ContentController
+ */
+class ContentController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
+{
+    /**
+     * @inject
+     * @var \ExtbaseTeam\BlogExample\Domain\Repository\TtContentRepository
+     */
+    protected $contentRepository;
+
+    /**
+     * @var string
+     */
+    protected $defaultViewObjectName = \TYPO3\CMS\Extbase\Mvc\View\JsonView::class;
+
+    /**
+     * @inject
+     * @var \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory
+     */
+    protected $dataMapFactory;
+
+    /**
+     * @return array
+     */
+    public function listAction()
+    {
+        $content = $this->contentRepository->findAll();
+        $value[$this->getRuntimeIdentifier()] = $this->getStructure($content);
+
+        $this->view->assign('value', $value);
+    }
+
+    /**
+     * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request
+     * @param \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response
+     * @throws \RuntimeException
+     */
+    public function processRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request, \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response)
+    {
+        try {
+            parent::processRequest($request, $response);
+        } catch (\TYPO3\CMS\Extbase\Property\Exception $exception) {
+            throw new \RuntimeException(
+                $this->getRuntimeIdentifier() . ': ' . $exception->getMessage() . ' (' . $exception->getCode() . ')',
+                1476122223
+            );
+        }
+    }
+
+    /**
+     * @param \Iterator|\TYPO3\CMS\Extbase\DomainObject\AbstractEntity[] $iterator
+     * @return array
+     */
+    protected function getStructure($iterator)
+    {
+        $structure = [];
+
+        if (!$iterator instanceof \Iterator) {
+            $iterator = [$iterator];
+        }
+
+        foreach ($iterator as $entity) {
+            $dataMap = $this->dataMapFactory->buildDataMap(get_class($entity));
+            $tableName = $dataMap->getTableName();
+            $identifier = $tableName . ':' . $entity->getUid();
+            $properties = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getGettableProperties($entity);
+
+            $structureItem = [];
+            foreach ($properties as $propertyName => $propertyValue) {
+                $columnMap = $dataMap->getColumnMap($propertyName);
+                if ($columnMap !== null) {
+                    $propertyName = $columnMap->getColumnName();
+                }
+                if ($propertyValue instanceof \Iterator) {
+                    $structureItem[$propertyName] = $this->getStructure($propertyValue);
+                } else {
+                    $structureItem[$propertyName] = $propertyValue;
+                }
+            }
+            $structure[$identifier] = $structureItem;
+        }
+
+        return $structure;
+    }
+
+    /**
+     * @return string
+     */
+    protected function getRuntimeIdentifier()
+    {
+        $arguments = [];
+        foreach ($this->request->getArguments() as $argumentName => $argumentValue) {
+            $arguments[] = $argumentName . '=' . $argumentValue;
+        }
+        return $this->request->getControllerActionName() . '(' . implode(', ', $arguments) . ')';
+    }
+}
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/TtContent.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/TtContent.php
new file mode 100644 (file)
index 0000000..94aa210
--- /dev/null
@@ -0,0 +1,122 @@
+<?php
+namespace ExtbaseTeam\BlogExample\Domain\Model;
+
+/*
+ * 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!
+ */
+
+/**
+ * A tt_content model
+ */
+class TtContent extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
+{
+    /**
+     * uid
+     *
+     * @var string
+     */
+    protected $uid = '';
+
+    /**
+     * pid
+     *
+     * @var string
+     */
+    protected $pid = '';
+
+    /**
+     * @var string
+     */
+    protected $header;
+
+    /**
+     * Images
+     *
+     * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference>
+     * @lazy
+     */
+    protected $image;
+
+    /**
+     * Constructs this post
+     */
+    public function __construct()
+    {
+        $this->image = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
+    }
+
+    /**
+     * Gets the uid
+     *
+     * @return string $uid
+     */
+    public function getUid()
+    {
+        return $this->uid;
+    }
+
+    /**
+     * Gets the pid
+     *
+     * @return string $pid
+     */
+    public function getPid()
+    {
+        return $this->pid;
+    }
+
+    /**
+     * Returns the header
+     *
+     * @return string $header
+     */
+    public function getHeader()
+    {
+        return $this->header;
+    }
+
+    /**
+     * Sets the header
+     *
+     * @param string $header
+     */
+    public function setHeader($header)
+    {
+        $this->header = $header;
+    }
+
+    /**
+     * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage
+     */
+    public function getImage()
+    {
+        return $this->image;
+    }
+
+    /**
+     * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $image
+     */
+    public function setImage(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $image)
+    {
+        $this->image = $image;
+    }
+
+    /**
+     * Returns this as a formatted string
+     *
+     * @return string
+     */
+    public function __toString()
+    {
+        return $this->getHeader();
+    }
+}
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Repository/TtContentRepository.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Repository/TtContentRepository.php
new file mode 100644 (file)
index 0000000..f47e7e8
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+namespace ExtbaseTeam\BlogExample\Domain\Repository;
+
+/*
+ * 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 TYPO3\CMS\Extbase\Persistence\QueryInterface;
+
+/**
+ * A repository for tt_contents
+ */
+class TtContentRepository extends \TYPO3\CMS\Extbase\Persistence\Repository
+{
+}
index 05cff59..cf248f0 100644 (file)
@@ -8,3 +8,10 @@ defined('TYPO3_MODE') or die();
     ],
     []
 );
+\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
+    'ExtbaseTeam.' . $_EXTKEY, 'Content',
+    [
+        'Content' => 'list',
+    ],
+    []
+);
index c3f0d3a..05a8066 100644 (file)
@@ -14,6 +14,16 @@ config.tx_extbase {
                                        recordType = ExtbaseTeam\BlogExample\Domain\Model\Administrator
                                }
                        }
+                       ExtbaseTeam\BlogExample\Domain\Model\TtContent {
+                               mapping {
+                                       tableName = tt_content
+                                       columns {
+                                               uid.mapOnProperty = uid
+                                               pid.mapOnProperty = pid
+                                               header.mapOnProperty = header
+                                       }
+                               }
+                       }
                }
        }
 }
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/Frontend/ContentJsonRenderer.ts b/typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/Frontend/ContentJsonRenderer.ts
new file mode 100644 (file)
index 0000000..af112e1
--- /dev/null
@@ -0,0 +1,44 @@
+config {
+       no_cache = 1
+       debug = 0
+       xhtml_cleaning = 0
+       admPanel = 0
+       disableAllHeaderCode = 1
+       sendCacheHeaders = 0
+       sys_language_uid = 0
+       additionalHeaders = Content-Type: application/json; charset=utf-8
+}
+
+plugin.tx_blogexample {
+       persistence {
+               storagePid = 89
+       }
+}
+
+page = PAGE
+page {
+       10 = COA
+       10 {
+               10 = USER
+               10 {
+                       userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run
+                       extensionName = BlogExample
+                       pluginName = Content
+                       vendorName = ExtbaseTeam
+               }
+               stdWrap.postUserFunc = TYPO3\CMS\Core\Tests\Functional\Framework\Frontend\Renderer->parseValues
+               stdWrap.postUserFunc.as = Extbase
+       }
+
+       stdWrap.postUserFunc = TYPO3\CMS\Core\Tests\Functional\Framework\Frontend\Renderer->renderSections
+}
+
+[globalVar = GP:L = 1]
+       config.sys_language_uid = 1
+[end]
+[globalVar = GP:L = 2]
+       config.sys_language_uid = 2
+[end]
+[globalVar = GP:L = 3]
+       config.sys_language_uid = 3
+[end]
diff --git a/typo3/sysext/extbase/Tests/Functional/Persistence/TranslatedContentTest.php b/typo3/sysext/extbase/Tests/Functional/Persistence/TranslatedContentTest.php
new file mode 100644 (file)
index 0000000..1935ac5
--- /dev/null
@@ -0,0 +1,598 @@
+<?php
+
+namespace TYPO3\CMS\Extbase\Tests\Functional\Persistence;
+
+/*
+ * 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 TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Response;
+
+/**
+ * This test is an Extbase version of the \TYPO3\CMS\Frontend\Tests\Functional\Rendering\LocalizedContentRenderingTest
+ * scenarios are the same, just a way of fetching content is different
+ *
+ * This test documents current behaviour of extbase which is inconsistent with TypoScript rendering of tt_content.
+ */
+class TranslatedContentTest extends \TYPO3\CMS\Core\Tests\Functional\DataHandling\AbstractDataHandlerActionTestCase
+{
+    const VALUE_PageId = 89;
+    const TABLE_Content = 'tt_content';
+    const TABLE_Pages = 'pages';
+
+    /**
+     * @var string
+     */
+    protected $scenarioDataSetDirectory = 'typo3/sysext/frontend/Tests/Functional/Rendering/DataSet/';
+
+    /**
+     * @var array
+     */
+    protected $testExtensionsToLoad = ['typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example'];
+
+    /**
+     * @var array
+     */
+    protected $coreExtensionsToLoad = ['extbase', 'fluid'];
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface The object manager
+     */
+    protected $objectManager;
+
+    /**
+     * @var \ExtbaseTeam\BlogExample\Domain\Repository\TtContentRepository
+     */
+    protected $contentRepository;
+
+    /**
+     * Custom 404 handler returning valid json is registered so the $this->getFrontendResponse()
+     * does not fail on 404 pages
+     *
+     * @var array
+     */
+    protected $configurationToUseInTestInstance = [
+        'FE' => [
+            'pageNotFound_handling' => 'READFILE:typo3/sysext/frontend/Tests/Functional/Rendering/DataSet/404Template.html'
+        ]
+    ];
+
+    protected function setUp()
+    {
+        parent::setUp();
+        $this->importScenarioDataSet('LiveDefaultPages');
+        $this->importScenarioDataSet('LiveDefaultElements');
+
+        $this->backendUser->workspace = 0;
+        $this->objectManager = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class);
+        $this->contentRepository = $this->objectManager->get(\ExtbaseTeam\BlogExample\Domain\Repository\TtContentRepository::class);
+        $this->setUpFrontendRootPage(1, [
+            'typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TypoScript/setup.txt',
+            'typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/Frontend/ContentJsonRenderer.ts'
+        ]);
+    }
+
+    public function defaultLanguageConfigurationDataProvider()
+    {
+        return [
+            [
+                'typoScript' => 'config.sys_language_overlay = 0
+                                config.sys_language_mode =',
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 0
+                                config.sys_language_mode = content_fallback',
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 0
+                                config.sys_language_mode = content_fallback;1,0',
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 0
+                                config.sys_language_mode = strict',
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 0
+                                config.sys_language_mode = ignore',
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 1
+                                config.sys_language_mode =',
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 1
+                                config.sys_language_mode = content_fallback',
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 1
+                                config.sys_language_mode = content_fallback;1,0',
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 1
+                                config.sys_language_mode = strict',
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 1
+                                config.sys_language_mode = ignore',
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = hideNonTranslated
+                                config.sys_language_mode =',
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = hideNonTranslated
+                                config.sys_language_mode = content_fallback',
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = hideNonTranslated
+                                config.sys_language_mode = content_fallback;1,0',
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = hideNonTranslated
+                                config.sys_language_mode = strict',
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = hideNonTranslated
+                                config.sys_language_mode = ignore',
+            ],
+        ];
+    }
+
+    /**
+     * For the default language all combination of language settings should give the same result,
+     * regardless of TypoScript settings, if the requested language is "0" then no TypoScript settings apply.
+     *
+     * @test
+     * @dataProvider defaultLanguageConfigurationDataProvider
+     *
+     * @param string $typoScript
+     */
+    public function onlyEnglishContentIsRenderedForDefaultLanguage( $typoScript)
+    {
+        $this->addTypoScriptToTemplateRecord(1, $typoScript);
+
+        $frontendResponse = $this->getFrontendResponse(self::VALUE_PageId, 0);
+        $responseSections = $frontendResponse->getResponseSections('Extbase:list()');
+        $visibleHeaders = ['Regular Element #1', 'Regular Element #2', 'Regular Element #3'];
+
+        $constraint = $this->getRequestSectionHasRecordConstraint()
+            ->setTable(self::TABLE_Content)
+            ->setField('header');
+        call_user_func_array([$constraint, 'setValues'], $visibleHeaders);
+        $this->assertThat($responseSections, $constraint);
+
+        $constraint = $this->getRequestSectionDoesNotHaveRecordConstraint()
+            ->setTable(self::TABLE_Content)
+            ->setField('header');
+        call_user_func_array([$constraint, 'setValues'], $this->getNonVisibleHeaders($visibleHeaders));
+        $this->assertThat($responseSections, $constraint);
+    }
+
+    /**
+     * Dutch language has pages_language_overlay record and some content elements are translated
+     *
+     * @return array
+     */
+    public function dutchDataProvider()
+    {
+        //Expected behaviour:
+        //Page is translated to Dutch, so changing sys_language_mode does NOT change the results
+        //Page title is always [DK]Page, and both sys_language_content and sys_language_uid are always 1
+        return [
+            [
+                'typoScript' => 'config.sys_language_overlay = 0
+                                config.sys_language_mode =',
+                'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', 'Regular Element #2', '[DK] UnHidden Element #4'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 0
+                                config.sys_language_mode = content_fallback',
+                'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', 'Regular Element #2', '[DK] UnHidden Element #4'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 0
+                                config.sys_language_mode = content_fallback;1,0',
+                'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', 'Regular Element #2', '[DK] UnHidden Element #4'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 0
+                                config.sys_language_mode = strict',
+                'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 0
+                                config.sys_language_mode = ignore',
+                'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', 'Regular Element #2', '[DK] UnHidden Element #4'],
+            ],
+            5 => [
+                'typoScript' => 'config.sys_language_overlay = 1
+                                config.sys_language_mode =',
+                'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', 'Regular Element #2', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', '[DK] UnHidden Element #4'],
+            ],
+//             Expected behaviour:
+//             Not translated element #2 is shown because sys_language_overlay = 1 (with sys_language_overlay = hideNonTranslated, it would be hidden)
+            [
+                'typoScript' => 'config.sys_language_overlay = 1
+                                config.sys_language_mode = content_fallback',
+                'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', 'Regular Element #2', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', '[DK] UnHidden Element #4'],
+            ],
+//             Expected behaviour:
+//             Same as config.sys_language_mode = content_fallback because we're requesting language 1, so no additional fallback possible
+
+            [
+                'typoScript' => 'config.sys_language_overlay = 1
+                                config.sys_language_mode = content_fallback;1,0',
+                'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', 'Regular Element #2', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', '[DK] UnHidden Element #4'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 1
+                                config.sys_language_mode = strict',
+                'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 1
+                                config.sys_language_mode = ignore',
+                'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', 'Regular Element #2', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', '[DK] UnHidden Element #4'],
+            ],
+//             Expected behaviour:
+//             Non translated default language elements are not shown, because of hideNonTranslated
+            10 => [
+                'typoScript' => 'config.sys_language_overlay = hideNonTranslated
+                                config.sys_language_mode =',
+                'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', 'Regular Element #2', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', '[DK] UnHidden Element #4'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = hideNonTranslated
+                                config.sys_language_mode = content_fallback',
+                'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', 'Regular Element #2', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', '[DK] UnHidden Element #4'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = hideNonTranslated
+                                config.sys_language_mode = content_fallback;1,0',
+                'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', 'Regular Element #2', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', '[DK] UnHidden Element #4'],
+            ],
+//            Setting sys_language_mode = strict has the same effect as previous data sets, because the translation of the page exists
+            [
+                'typoScript' => 'config.sys_language_overlay = hideNonTranslated
+                                config.sys_language_mode = strict',
+                'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = hideNonTranslated
+                                config.sys_language_mode = ignore',
+                'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', 'Regular Element #2', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', '[DK] UnHidden Element #4'],
+            ],
+        ];
+    }
+
+    /**
+     * @test
+     * @dataProvider dutchDataProvider
+     *
+     * @param string $typoScript
+     * @param array $visibleHeaders
+     */
+    public function renderingOfDutchLanguage($typoScript, array $visibleHeaders)
+    {
+        $this->addTypoScriptToTemplateRecord(1, $typoScript);
+        $frontendResponse = $this->getFrontendResponse(self::VALUE_PageId, 1);
+        $responseSections = $frontendResponse->getResponseSections('Extbase:list()');
+        $constraint = $this->getRequestSectionHasRecordConstraint()
+            ->setTable(self::TABLE_Content)
+            ->setField('header');
+        call_user_func_array([$constraint, 'setValues'], $visibleHeaders);
+        $this->assertThat($responseSections, $constraint);
+
+        $constraint = $this->getRequestSectionDoesNotHaveRecordConstraint()
+            ->setTable(self::TABLE_Content)
+            ->setField('header');
+        call_user_func_array([$constraint, 'setValues'], $this->getNonVisibleHeaders($visibleHeaders));
+        $this->assertThat($responseSections, $constraint);
+    }
+
+    public function contentOnNonTranslatedPageDataProvider()
+    {
+        //Expected behaviour:
+        //the page is NOT translated so setting sys_language_mode to different values changes the results
+        //- setting sys_language_mode to empty value makes TYPO3 return default language records
+        //- setting it to strict throws 404, independently from other settings
+        //Setting config.sys_language_overlay = 0
+        return [
+            [
+                'typoScript' => 'config.sys_language_overlay = 0
+                                config.sys_language_mode =',
+                'visibleRecordHeaders' => ['Regular Element #1', 'Regular Element #2', 'Regular Element #3'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 0
+                                config.sys_language_mode = content_fallback',
+                'visibleRecordHeaders' => ['Regular Element #1', 'Regular Element #2', 'Regular Element #3'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 0
+                                config.sys_language_mode = content_fallback;1,0',
+                'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', 'Regular Element #2', '[Translate to Dansk:] Regular Element #3', '[DK] UnHidden Element #4', '[DK] Without default language'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 0
+                                config.sys_language_mode = strict',
+                'visibleRecordHeaders' => [],
+                'status' => 404,
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 0
+                                config.sys_language_mode = ignore',
+                'visibleRecordHeaders' => ['[Translate to Deutsch:] [Translate to Dansk:] Regular Element #1', 'Regular Element #2', 'Regular Element #3', '[DE] Without default language'],
+            ],
+            5 => [
+                'typoScript' => 'config.sys_language_overlay = 1
+                                config.sys_language_mode =',
+                'visibleRecordHeaders' => ['Regular Element #1', 'Regular Element #2', 'Regular Element #3'],
+            ],
+            //falling back to default language
+            [
+                'typoScript' => 'config.sys_language_overlay = 1
+                                config.sys_language_mode = content_fallback',
+                'visibleRecordHeaders' => ['Regular Element #1', 'Regular Element #2', 'Regular Element #3'],
+            ],
+            //Dutch elements are shown because of the content fallback 1,0 - first Dutch, then default language
+            //note that '[DK] Without default language' is NOT shown - due to overlays (fetch default language and overlay it with translations)
+            [
+                'typoScript' => 'config.sys_language_overlay = 1
+                                config.sys_language_mode = content_fallback;1,0',
+                'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', 'Regular Element #2', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', '[DK] UnHidden Element #4'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 1
+                                config.sys_language_mode = strict',
+                'visibleRecordHeaders' => [],
+                'status' => 404
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 1
+                                config.sys_language_mode = ignore',
+                'visibleRecordHeaders' => ['[Translate to Deutsch:] [Translate to Dansk:] Regular Element #1', 'Regular Element #2', 'Regular Element #3', '[DE] Without default language'],
+            ],
+            10 => [
+                'typoScript' => 'config.sys_language_overlay = hideNonTranslated
+                                config.sys_language_mode =',
+                'visibleRecordHeaders' => ['Regular Element #1', 'Regular Element #2', 'Regular Element #3'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = hideNonTranslated
+                                config.sys_language_mode = content_fallback',
+                'visibleRecordHeaders' => ['Regular Element #1', 'Regular Element #2', 'Regular Element #3'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = hideNonTranslated
+                                config.sys_language_mode = content_fallback;1,0',
+                'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', '[Translate to Dansk:] Regular Element #3', 'Regular Element #2', '[DK] Without default language', '[DK] UnHidden Element #4'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = hideNonTranslated
+                                config.sys_language_mode = strict',
+                'visibleRecordHeaders' => [],
+                'status' => 404,
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = hideNonTranslated
+                                config.sys_language_mode = ignore',
+                'visibleRecordHeaders' => ['[Translate to Deutsch:] [Translate to Dansk:] Regular Element #1', 'Regular Element #2', 'Regular Element #3', '[DE] Without default language'],
+            ],
+        ];
+    }
+
+    /**
+     * Page uid 89 is NOT translated to german
+     *
+     * @test
+     * @dataProvider contentOnNonTranslatedPageDataProvider
+     *
+     * @param string $typoScript
+     * @param array $visibleHeaders
+     * @param string $status 'success' or 404
+     */
+    public function contentOnNonTranslatedPageGerman($typoScript, array $visibleHeaders, $status='success')
+    {
+        $this->addTypoScriptToTemplateRecord(1, $typoScript);
+
+        $frontendResponse = $this->getFrontendResponse(self::VALUE_PageId, 2);
+        if ($status === 'success') {
+            $responseSections = $frontendResponse->getResponseSections('Extbase:list()');
+            $constraint = $this->getRequestSectionHasRecordConstraint()
+                ->setTable(self::TABLE_Content)
+                ->setField('header');
+            call_user_func_array([$constraint, 'setValues'], $visibleHeaders);
+            $this->assertThat($responseSections, $constraint);
+
+            $constraint = $this->getRequestSectionDoesNotHaveRecordConstraint()
+                ->setTable(self::TABLE_Content)
+                ->setField('header');
+            call_user_func_array([$constraint, 'setValues'], $this->getNonVisibleHeaders($visibleHeaders));
+            $this->assertThat($responseSections, $constraint);
+        }
+        //some configuration combinations results in 404, in that case status will be set to 404
+        $this->assertEquals($status, $frontendResponse->getStatus());
+    }
+
+    public function contentOnPartiallyTranslatedPageDataProvider()
+    {
+
+        //Expected behaviour:
+        //Setting sys_language_mode to different values doesn't influence the result as the requested page is translated to Polish,
+        //Page title is always [PL]Page, and both sys_language_content and sys_language_uid are always 3
+        return [
+            [
+                'typoScript' => 'config.sys_language_overlay = 0
+                                config.sys_language_mode =',
+                'visibleRecordHeaders' => ['Regular Element #3', '[Translate to Polski:] Regular Element #1', '[PL] Without default language'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 0
+                                config.sys_language_mode = content_fallback',
+                'visibleRecordHeaders' => ['Regular Element #3', '[Translate to Polski:] Regular Element #1', '[PL] Without default language'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 0
+                                config.sys_language_mode = content_fallback;1,0',
+                'visibleRecordHeaders' => ['Regular Element #3', '[Translate to Polski:] Regular Element #1', '[PL] Without default language'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 0
+                                config.sys_language_mode = strict',
+                'visibleRecordHeaders' => ['[Translate to Polski:] Regular Element #1', '[PL] Without default language'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 0
+                                config.sys_language_mode = ignore',
+                'visibleRecordHeaders' => ['Regular Element #3', '[Translate to Polski:] Regular Element #1', '[PL] Without default language'],
+            ],
+            5 => [
+                'typoScript' => 'config.sys_language_overlay = 1
+                                config.sys_language_mode =',
+                'visibleRecordHeaders' => ['[PL] Without default language', '[Translate to Polski:] Regular Element #1', 'Regular Element #3'],
+            ],
+            // Expected behaviour:
+            // Not translated element #2 is shown because sys_language_overlay = 1 (with sys_language_overlay = hideNonTranslated, it would be hidden)
+            [
+                'typoScript' => 'config.sys_language_overlay = 1
+                                config.sys_language_mode = content_fallback',
+                'visibleRecordHeaders' => ['[PL] Without default language', '[Translate to Polski:] Regular Element #1', 'Regular Element #3'],
+            ],
+//             Expected behaviour:
+//             Element #3 is not translated in PL and it is translated in DK. It's not shown as content_fallback is not related to single CE level
+//             but on page level - and this page is translated to Polish, so no fallback is happening
+            [
+                'typoScript' => 'config.sys_language_overlay = 1
+                                config.sys_language_mode = content_fallback;1,0',
+                'visibleRecordHeaders' => ['[PL] Without default language', '[Translate to Polski:] Regular Element #1', 'Regular Element #3'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 1
+                                config.sys_language_mode = strict',
+                'visibleRecordHeaders' => ['[PL] Without default language', '[Translate to Polski:] Regular Element #1'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = 1
+                                config.sys_language_mode = ignore',
+                'visibleRecordHeaders' => ['[PL] Without default language', '[Translate to Polski:] Regular Element #1', 'Regular Element #3'],
+            ],
+            // Expected behaviour:
+            // Non translated default language elements are not shown, because of hideNonTranslated
+            10 => [
+                'typoScript' => 'config.sys_language_overlay = hideNonTranslated
+                                config.sys_language_mode =',
+                'visibleRecordHeaders' => ['[PL] Without default language', 'Regular Element #3', '[Translate to Polski:] Regular Element #1'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = hideNonTranslated
+                                config.sys_language_mode = content_fallback',
+                'visibleRecordHeaders' => ['[PL] Without default language', 'Regular Element #3', '[Translate to Polski:] Regular Element #1'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = hideNonTranslated
+                                config.sys_language_mode = content_fallback;1,0',
+                'visibleRecordHeaders' => ['[PL] Without default language', 'Regular Element #3', '[Translate to Polski:] Regular Element #1'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = hideNonTranslated
+                                config.sys_language_mode = strict',
+                'visibleRecordHeaders' => ['[PL] Without default language', '[Translate to Polski:] Regular Element #1'],
+            ],
+            [
+                'typoScript' => 'config.sys_language_overlay = hideNonTranslated
+                                config.sys_language_mode = ignore',
+                'visibleRecordHeaders' => ['[PL] Without default language', 'Regular Element #3', '[Translate to Polski:] Regular Element #1'],
+            ]
+        ];
+    }
+
+    /**
+     * Page uid 89 is translated to to Polish, but not all CE are translated
+     *
+     * @test
+     * @dataProvider contentOnPartiallyTranslatedPageDataProvider
+     *
+     * @param string $typoScript
+     * @param array $visibleHeaders
+     */
+    public function contentOnPartiallyTranslatedPage($typoScript, array $visibleHeaders)
+    {
+        $this->addTypoScriptToTemplateRecord(1, $typoScript);
+
+        $frontendResponse = $this->getFrontendResponse(self::VALUE_PageId, 3);
+        $this->assertEquals('success', $frontendResponse->getStatus());
+        $responseSections = $frontendResponse->getResponseSections('Extbase:list()');
+
+        $constraint = $this->getRequestSectionHasRecordConstraint()
+            ->setTable(self::TABLE_Content)
+            ->setField('header');
+        call_user_func_array([$constraint, 'setValues'], $visibleHeaders);
+        $this->assertThat($responseSections, $constraint);
+
+        $constraint = $this->getRequestSectionDoesNotHaveRecordConstraint()
+            ->setTable(self::TABLE_Content)
+            ->setField('header');
+        call_user_func_array([$constraint, 'setValues'], $this->getNonVisibleHeaders($visibleHeaders));
+        $this->assertThat($responseSections, $constraint);
+    }
+
+    /**
+     * Helper function to ease asserting that rest of the data set is not visible
+     *
+     * @param array $visibleHeaders
+     * @return array
+     */
+    protected function getNonVisibleHeaders(array $visibleHeaders)
+    {
+        $allElements = [
+            'Regular Element #1',
+            'Regular Element #2',
+            'Regular Element #3',
+            'Hidden Element #4',
+            '[Translate to Dansk:] Regular Element #1',
+            '[Translate to Dansk:] Regular Element #3',
+            '[DK] Without default language',
+            '[DK] UnHidden Element #4',
+            '[DE] Without default language',
+            '[Translate to Deutsch:] [Translate to Dansk:] Regular Element #1',
+            '[Translate to Polski:] Regular Element #1',
+            '[PL] Without default language',
+            '[PL] Hidden Regular Element #2'
+        ];
+        return array_diff($allElements, $visibleHeaders);
+    }
+
+    /**
+     * Adds TypoScript setup snippet to the existing template record
+     *
+     * @param int $pageId
+     * @param string $typoScript
+     */
+    protected function addTypoScriptToTemplateRecord($pageId, $typoScript)
+    {
+        $connection = $this->getDatabaseConnection();
+
+        $template = $connection->exec_SELECTgetSingleRow('*', 'sys_template', 'pid = '. $pageId . ' AND root = 1');
+        if (empty($template)) {
+            $this->fail('Cannot find root template on page with id: "' . $pageId . '"');
+        }
+        $updateFields['config'] = $template['config'] . LF . $typoScript;
+        $connection->exec_UPDATEquery(
+            'sys_template',
+            'uid = ' . $template['uid'],
+            $updateFields
+        );
+    }
+}