Commit d1370d2c authored by Tymoteusz Motylewski's avatar Tymoteusz Motylewski Committed by Oliver Hader
Browse files

[TASK] Provide test for Page\TreeController

Add test for TreeController, so we're safe when refactoring
or doing performance optimizations.

Besides that moved pages in a workspace were not considered when
calculating permissions on the rootline due to missing workspace
overlays.

Resolves: #90831
Releases: 9.5, master
Change-Id: Ic3ab08d2502e8c9a3f08e737552c2e1d2a56a66c
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/63848


Tested-by: default avatarTYPO3com <noreply@typo3.com>
Tested-by: Oliver Hader's avatarOliver Hader <oliver.hader@typo3.org>
Reviewed-by: Oliver Hader's avatarOliver Hader <oliver.hader@typo3.org>
parent d202e68d
......@@ -88,7 +88,7 @@
"phpstan/phpstan": "^0.12.13",
"rector/rector": "~0.7",
"typo3/cms-styleguide": "~10.0.2",
"typo3/testing-framework": "^6.2.0"
"typo3/testing-framework": "^6.2.2"
},
"suggest": {
"ext-gd": "GDlib/Freetype is required for building images with text (GIFBUILDER) and can also be used to scale images",
......
......@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "e6e138201c43bbc6250fbd836633a21d",
"content-hash": "cd0e12abcab99e0526c2f9707df4f2d1",
"packages": [
{
"name": "cogpowered/finediff",
......@@ -8115,8 +8115,8 @@
"authors": [
{
"name": "Arne Blankerts",
"email": "arne@blankerts.de",
"role": "Developer"
"role": "Developer",
"email": "arne@blankerts.de"
}
],
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
......@@ -8259,16 +8259,16 @@
},
{
"name": "typo3/testing-framework",
"version": "6.2.0",
"version": "6.2.2",
"source": {
"type": "git",
"url": "https://github.com/TYPO3/testing-framework.git",
"reference": "d308d4263b3268873c8b4028d8b526f2862aca6c"
"reference": "4e14e564f72875ce4c4414dd390c4b5ddb071fe6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/TYPO3/testing-framework/zipball/d308d4263b3268873c8b4028d8b526f2862aca6c",
"reference": "d308d4263b3268873c8b4028d8b526f2862aca6c",
"url": "https://api.github.com/repos/TYPO3/testing-framework/zipball/4e14e564f72875ce4c4414dd390c4b5ddb071fe6",
"reference": "4e14e564f72875ce4c4414dd390c4b5ddb071fe6",
"shasum": ""
},
"require": {
......@@ -8280,7 +8280,7 @@
"typo3/cms-fluid": "10.*.*@dev",
"typo3/cms-frontend": "10.*.*@dev",
"typo3/cms-recordlist": "10.*.*@dev",
"typo3fluid/fluid": "^2.5"
"typo3fluid/fluid": "^2.5|^3"
},
"suggest": {
"codeception/codeception": "^4.0",
......@@ -8315,7 +8315,7 @@
"tests",
"typo3"
],
"time": "2020-03-03T13:18:50+00:00"
"time": "2020-04-06T15:19:47+00:00"
}
],
"aliases": [],
......
__variables:
- &pageStandard 0
- &pageShortcut 4
- &pageMount 7
- &pageFolder 254
- &contentText 'text'
- &idAcmeRootPage 1000
- &idAcmeFirstPage 1100
entitySettings:
'*':
nodeColumnName: 'pid'
columnNames: {id: 'uid', language: 'sys_language_uid'}
defaultValues: {pid: 0}
page:
isNode: true
tableName: 'pages'
parentColumnName: 'pid'
languageColumnNames: ['l10n_parent', 'l10n_source']
columnNames: {type: 'doktype', root: 'is_siteroot', mount: 'mount_pid', visitorGroups: 'fe_group'}
defaultValues: {hidden: 0, doktype: *pageStandard, perms_userid: 1, perms_groupid: 9}
valueInstructions:
shortcut:
first: {shortcut: 0, shortcut_mode: 1}
content:
tableName: 'tt_content'
languageColumnNames: ['l18n_parent', 'l10n_source']
columnNames: {title: 'header', type: 'CType'}
workspace:
tableName: 'sys_workspace'
language:
tableName: 'sys_language'
columnNames: {code: 'language_isocode'}
visitorGroup:
tableName: 'fe_groups'
visitor:
tableName: 'fe_users'
columnNames: {groups: 'usergroup'}
typoscript:
tableName: 'sys_template'
valueInstructions:
type:
site: {root: 1, clear: 1}
beGroup:
tableName: 'be_groups'
entities:
workspace:
- self: {id: 1, title: 'Workspace'}
language:
- self: {id: 1, title: 'French', code: 'fr'}
- self: {id: 2, title: 'Franco-Canadian', code: 'fr'}
- self: {id: 3, title: 'Spanish', code: 'es'}
beGroup:
- self: {id: 9, title: 'editors', db_mountpoints: '1000,2000', tables_select: 'pages,tt_content', tables_modify: 'pages,tt_content', page_types_select: '1,4,7,254', groupMods: 'web_layout,web_list'}
page:
- self: {id: *idAcmeRootPage, title: 'ACME Inc', type: *pageShortcut, shortcut: 'first', root: true, slug: '/'}
children:
- self: {id: *idAcmeFirstPage, title: 'EN: Welcome', slug: '/welcome', subtitle: 'hello-and-welcome'}
- self: {id: 1200, title: 'EN: Features', slug: '/features'}
children:
- self: {id: 1210, title: 'EN: Frontend Editing', slug: '/features/frontend-editing', perms_userid: 9, perms_groupid: 1, description: "accessible for user, but not for group"}
- self: {id: 1220, title: 'EN: Managing backend', slug: '/features/managing-backend', perms_userid: 1, perms_groupid: 1, description: "not accessible"}
- self: {id: 1230, title: 'EN: Managing content', slug: '/features/managing-content', perms_userid: 9, perms_groupid: 9, description: "accessible for user and group"}
- version: {id: 1240, title: 'EN: Managing data', slug: '/features/managing-data', workspace: 1}
children:
- version: {id: 124010, title: 'EN: Managing complex data', slug: '/features/managing-data/complex', workspace: 1}
- self: {id: 1400, title: 'EN: ACME in your Region', root: true, slug: '/acme-in-your-region'}
languageVariants:
- self: {id: 1401, title: 'FR: ACME in your Region', language: 1, slug: '/acme-dans-votre-region'}
- self: {id: 1402, title: 'FR-CA: ACME in your Region', language: 2, slug: '/acme-dans-votre-quebec'}
children:
- self: {id: 1410, title: 'EN: Groups', slug: '/acme-in-your-region/groups', l18n_cfg: 1}
languageVariants:
- self: {id: 1411, title: 'FR: Groups', language: 1, slug: '/acme-dans-votre-region/groupes'}
- self: {id: 1412, title: 'FR-CA: Groups', language: 2, slug: '/acme-dans-votre-quebec/groupes'}
- self: {id: 1500, title: 'Internal', slug: '/my-acme'}
children:
- self: {id: 1510, title: 'Whitepapers', visitorGroups: -2, extendToSubpages: true, slug: '/my-acme/whitepapers', perms_userid: 1, perms_groupid: 1, description: "not accessible"}
children:
- self: {id: 1511, title: 'Products', slug: '/my-acme/whitepapers/products'}
children:
- self: {id: 151110, title: 'Product 1', slug: '/my-acme/whitepapers/products/product-1'}
versionVariants:
- version: { workspace: 1 }
actions:
- { action: 'move', type: 'toPage', target: 1700 }
- self: {id: 1512, title: 'Solutions', visitorGroups: 10, slug: '/my-acme/whitepapers/solutions'}
children:
- self: {id: 151210, title: 'Solution 1', slug: '/my-acme/whitepapers/solutions/solution-1'}
- self: {id: 1515, title: 'Research', visitorGroups: 20, slug: '/my-acme/whitepapers/research'}
- self: {id: 1520, title: 'Forecasts', visitorGroups: 20, extendToSubpages: true, slug: '/my-acme/forecasts'}
children:
- self: {id: 1521, title: 'Current Year', slug: '/my-acme/forecasts/current-year'}
- self: {id: 1522, title: 'Next Year', slug: '/my-acme/forecasts/next-year'}
- self: {id: 1523, title: 'Five Years', slug: '/my-acme/forecasts/five-years'}
- self: {id: 1530, title: 'Reports', visitorGroups: 20, extendToSubpages: true, slug: '/my-acme/reports'}
languageVariants:
- version: {title: 'FR: Interne', workspace: 1, language: 1, slug: '/my-acme'}
- self: {id: 1600, title: 'About us', slug: '/about', perms_userid: 1, perms_groupid: 1, description: "not accessible"}
- self: {id: 1700, title: 'Announcements & News', type: *pageMount, mount: 7100, slug: '/news'}
- self: {id: 404, title: 'Page not found', slug: '/404'}
entities:
content:
- self: {title: 'EN: Page not found', type: *contentText}
- self: {id: 1930, title: 'Our Blog', type: *pageShortcut, shortcut: 2000, slug: '/blog'}
- version: {id: 1950, title: 'EN: Goodbye', workspace: 1, slug: '/bye'}
children:
- version: {title: 'EN: Really Goodbye', workspace: 1, slug: '/bye/bye'}
- self: {id: 1990, title: 'Storage', type: *pageFolder, slug: '/internal/storage'}
entities:
visitorGroup:
- self: {id: 10, title: 'Customers'}
- self: {id: 20, title: 'Partners'}
visitor:
- self: {id: 1, username: 'john@doe.local', groups: '10'}
- self: {id: 2, username: 'manager@other-inc.local', groups: '20'}
- self: {id: 3, username: 'big-boss@acme-inc.local', groups: '10,20'}
- self: {id: 2000, title: 'ACME Blog', type: *pageShortcut, shortcut: 'first', root: true, slug: '/', perms_userid: 1, perms_groupid: 1, description: "not accessible"}
children:
- self: {id: 2100, title: 'Authors', slug: '/authors'}
children:
- self: {id: 2110, title: 'John Doe', slug: '/john'}
children:
- self: {id: 2111, title: 'About', slug: '/about-john'}
- self: {id: 2120, title: 'Jane Doe', slug: '/jane'}
children:
- self: {id: 2121, title: 'About', slug: '/about-jane'}
- self: {id: 2700, title: 'Announcements & News', type: *pageMount, mount: 7100, slug: '/news'}
- self: {id: 2930, title: 'ACME Inc', type: *pageShortcut, shortcut: 1000, slug: '/acme'}
- self: {id: 7000, title: 'Common Collection', type: *pageFolder, root: true, slug: '/common'}
children:
- self: {id: 7100, title: 'Announcements & News', slug: '/common/news'}
children:
- self: {id: 7110, title: 'Markets', slug: '/common/markets'}
- self: {id: 7120, title: 'Products', slug: '/common/products'}
- self: {id: 7130, title: 'Partners', slug: '/common/partners'}
<?php
declare(strict_types = 1);
namespace TYPO3\CMS\Backend\Tests\Functional\Controller\Page;
/*
* 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\Backend\Controller\Page\TreeController;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Context\UserAspect;
use TYPO3\CMS\Core\Context\WorkspaceAspect;
use TYPO3\CMS\Core\Core\Bootstrap;
use TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\TestingFramework\Core\AccessibleObjectInterface;
use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerFactory;
use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerWriter;
use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
/**
* Test case for TYPO3\CMS\Backend\Controller\Page\TreeController
*/
class TreeControllerTest extends FunctionalTestCase
{
use SiteBasedTestTrait;
/**
* @var string[]
*/
protected $coreExtensionsToLoad = ['workspaces'];
/**
* @var TreeController|AccessibleObjectInterface
*/
private $subject;
/**
* @var BackendUserAuthentication
*/
private $backendUser;
/**
* @var BackendUserAuthentication
*/
private $regularBackendUser;
/**
* @var Context
*/
private $context;
/**
* The fixture which is used when initializing a backend user
*
* @var string
*/
protected $backendUserFixture = 'EXT:core/Tests/Functional/Fixtures/be_users.xml';
protected function setUp(): void
{
parent::setUp();
//admin user for importing dataset
$this->backendUser = $this->setUpBackendUserFromFixture(1);
$this->setUpDatabase();
//regular editor, non admin
$this->backendUser = $this->setUpBackendUser(9);
$this->context = GeneralUtility::makeInstance(Context::class);
$this->context->setAspect('backend.user', GeneralUtility::makeInstance(UserAspect::class, $this->backendUser));
$this->subject = $this->getAccessibleMock(TreeController::class, ['dummy']);
}
protected function tearDown(): void
{
unset($this->subject, $this->backendUser, $this->context);
parent::tearDown();
}
protected function setUpDatabase()
{
Bootstrap::initializeLanguageObject();
$scenarioFile = __DIR__ . '/Fixtures/PagesWithBEPermissions.yaml';
$factory = DataHandlerFactory::fromYamlFile($scenarioFile);
$writer = DataHandlerWriter::withBackendUser($this->backendUser);
$writer->invokeFactory($factory);
static::failIfArrayIsNotEmpty(
$writer->getErrors()
);
}
/**
* @test
*/
public function getAllEntryPointPageTrees()
{
$actual = $this->subject->_call('getAllEntryPointPageTrees');
$keepProperties = array_flip(['uid', 'title', '_children']);
$actual = $this->sortTreeArray($actual);
$actual = $this->normalizeTreeArray($actual, $keepProperties);
$expected = [
[
'uid' => 1000,
'title' => 'ACME Inc',
'_children' => [
[
'uid' => 1100,
'title' => 'EN: Welcome',
'_children' => [
],
],
[
'uid' => 1200,
'title' => 'EN: Features',
'_children' => [
[
'uid' => 1210,
'title' => 'EN: Frontend Editing',
'_children' => [
],
],
[
'uid' => 1230,
'title' => 'EN: Managing content',
'_children' => [
],
],
],
],
[
'uid' => 1400,
'title' => 'EN: ACME in your Region',
'_children' => [
[
'uid' => 1410,
'title' => 'EN: Groups',
'_children' => [
],
],
],
],
[
'uid' => 1500,
'title' => 'Internal',
'_children' => [
[
'uid' => 1520,
'title' => 'Forecasts',
'_children' => [
[
'uid' => 1521,
'title' => 'Current Year',
'_children' => [
],
],
[
'uid' => 1522,
'title' => 'Next Year',
'_children' => [
],
],
[
'uid' => 1523,
'title' => 'Five Years',
'_children' => [
],
],
],
],
[
'uid' => 1530,
'title' => 'Reports',
'_children' => [
],
],
],
],
[
'uid' => 1700,
'title' => 'Announcements & News',
'_children' => [
],
],
[
'uid' => 404,
'title' => 'Page not found',
'_children' => [
],
],
[
'uid' => 1930,
'title' => 'Our Blog',
'_children' => [
],
],
[
'uid' => 1990,
'title' => 'Storage',
'_children' => [
],
],
],
],
];
self::assertEquals($expected, $actual);
}
/**
* @test
*/
public function getAllEntryPointPageTreesInWorkspace()
{
$this->setWorkspace(1);
$actual = $this->subject->_call('getAllEntryPointPageTrees');
$keepProperties = array_flip(['uid', 'title', '_children']);
$actual = $this->sortTreeArray($actual);
$actual = $this->normalizeTreeArray($actual, $keepProperties);
$expected = [
[
'uid' => 1000,
'title' => 'ACME Inc',
'_children' => [
[
'uid' => 1950,
'title' => 'EN: Goodbye',
'_children' => [
[
'uid' => 10007,
'title' => 'EN: Really Goodbye',
'_children' => [
],
],
],
],
[
'uid' => 1100,
'title' => 'EN: Welcome',
'_children' => [
],
],
[
'uid' => 1200,
'title' => 'EN: Features',
'_children' => [
[
'uid' => 1240,
'title' => 'EN: Managing data',
'_children' => [
[
'uid' => 124010,
'title' => 'EN: Managing complex data',
'_children' => [
],
],
],
],
[
'uid' => 1210,
'title' => 'EN: Frontend Editing',
'_children' => [
],
],
[
'uid' => 1230,
'title' => 'EN: Managing content',
'_children' => [
],
],
],
],
[
'uid' => 1400,
'title' => 'EN: ACME in your Region',
'_children' => [
[
'uid' => 1410,
'title' => 'EN: Groups',
'_children' => [
],
],
],
],
[
'uid' => 1500,
'title' => 'Internal',
'_children' => [
[
'uid' => 1520,
'title' => 'Forecasts',
'_children' => [
[
'uid' => 1521,
'title' => 'Current Year',
'_children' => [
],
],
[
'uid' => 1522,
'title' => 'Next Year',
'_children' => [
],
],
[
'uid' => 1523,
'title' => 'Five Years',
'_children' => [
],
],
],
],
[
'uid' => 1530,
'title' => 'Reports',
'_children' => [
],
],
],
],
[
'uid' => 1700,
'title' => 'Announcements & News',
'_children' => [
[
// page with sub-pages moved in workspace 1
// from pid 1510 (missing permissions) to pid 1700 (visible now)
'uid' => 1511,
'title' => 'Products',
'_children' => [
[
'uid' => 151110,
'title' => 'Product 1',
'_children' => [],
]
],
],
],
],
[
'uid' => 404,
'title' => 'Page not found',
'_children' => [
],
],
[
'uid' => 1930,
'title' => 'Our Blog',
'_children' => [
],
],
[
'uid' => 1990,
'title' => 'Storage',
'_children' => [