diff --git a/Classes/Command/AcceptanceTestsCommand.php b/Classes/Command/AcceptanceTestsCommand.php
new file mode 100644
index 0000000..3a4c1b6
--- /dev/null
+++ b/Classes/Command/AcceptanceTestsCommand.php
@@ -0,0 +1,199 @@
+setDescription('Prepare extensions to run acceptance tests');
+ $this->filesystem = GeneralUtility::makeInstance(Filesystem::class);
+ }
+
+ /**
+ * @throws \JsonException
+ */
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ $this->package = $this->packageResolver->resolvePackage($this->askForExtensionKey());
+
+ $packageKey = $this->package->getPackageKey();
+ $targetPackagePath = $this->package->getPackagePath();
+
+ if ($this->updateComposerFile($targetPackagePath)) {
+ $this->io->writeln('Updated composer.json for EXT:' . $packageKey . '');
+ } else {
+ $this->io->writeln('Failed to update composer.json for EXT:' . $packageKey . '');
+ }
+
+ $this->io->writeln('Selected package: ' . $packageKey);
+ $finder = GeneralUtility::makeInstance(Finder::class);
+
+ $codeTemplatePath = '/Resources/Private/CodeTemplates/AcceptanceTests';
+ $templatePath = $this->packageResolver->resolvePackage('b13/make')->getPackagePath() . $codeTemplatePath;
+
+ $this->filesystem->mkdir([
+ $targetPackagePath . '/Tests/Acceptance/Fixtures',
+ $targetPackagePath . '/Tests/Acceptance/Application',
+ $targetPackagePath . '/Tests/Acceptance/Support/Extension'
+ ]);
+
+ // Create public folder which is required for e.g. acceptance tests to work
+ $publicFolderPath = $targetPackagePath . '/Resources/Public';
+ if (!is_dir($publicFolderPath)) {
+ $createPublic = $this->io->confirm(
+ 'Resource/Public is necessary e.g. for acceptance tests. Do you want to create it now?',
+ true
+ );
+
+ if ($createPublic) {
+ $this->filesystem->mkdir([$publicFolderPath]);
+ // Ensure the folder will be detected by git and committed
+ $this->filesystem->touch([$publicFolderPath . '/.gitkeep']);
+ }
+ }
+
+ $files = $finder->in($templatePath)->files();
+
+ foreach ($files as $file) {
+ $target = $targetPackagePath . 'Tests' . explode('AcceptanceTests', $file->getRealPath())[1];
+
+ if (!is_file($target)) {
+ $content = $file->getContents();
+ $this->substituteMarkersAndSave($content, $target);
+ } else {
+ $overwrite = $this->io->confirm('File exists ' . basename($target) . '. Do you want to overwrite it?');
+ if ($overwrite) {
+ $content = $file->getContents();
+ $this->substituteMarkersAndSave($content, $target);
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ /**
+ * Extend/prepare composer.json of the extension
+ * for acceptance tests
+ *
+ * @throws \JsonException
+ */
+ protected function updateComposerFile(string $packagePath): bool
+ {
+ $composerFile = $packagePath . '/composer.json';
+ $composerJson = file_get_contents($composerFile);
+ $composer = json_decode($composerJson, true);
+ if (json_last_error() !== JSON_ERROR_NONE) {
+ throw new \JsonException('Could not parse ' . $composerFile);
+ }
+
+ $namespace = rtrim($this->getNamespace(), '\\');
+
+ $addToComposerFile = [
+ 'require-dev' => [
+ 'codeception/codeception' => '^4.1',
+ 'codeception/module-asserts' => '^1.2',
+ 'codeception/module-webdriver' => '^1.1',
+ 'typo3/testing-framework' => '^6.16.2'
+ ],
+ 'autoload-dev' => [
+ 'psr-4' => [
+ $namespace . '\\Tests\\' => 'Tests/'
+ ]
+ ],
+ 'config' => [
+ 'vendor-dir' => '.Build/vendor',
+ 'bin-dir' => '.Build/bin',
+ ],
+ 'extra' => [
+ 'typo3/cms' => [
+ 'app-dir' => '.Build',
+ 'web-dir' => '.Build/Web',
+ ]
+ ]
+ ];
+
+ $enhancedComposer = $this->enhanceComposerFile($composer, $addToComposerFile);
+
+ return GeneralUtility::writeFile($composerFile, json_encode($enhancedComposer, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), true);
+ }
+
+ /**
+ * Substitute marker values and save file to extension_key/Tests/
+ *
+ * @param string $content
+ * @param string $target
+ */
+ protected function substituteMarkersAndSave(string $content, string $target): void
+ {
+ $markerService = GeneralUtility::makeInstance(MarkerBasedTemplateService::class);
+ $templateContent = $markerService->substituteMarker(
+ $content,
+ '{{NAMESPACE}}',
+ rtrim($this->getNamespace(), '\\')
+ );
+ $templateContent = $markerService->substituteMarker(
+ $templateContent,
+ '{{EXTENSION_KEY}}',
+ $this->package->getPackageKey()
+ );
+
+ try {
+ $this->filesystem->dumpFile($target, $templateContent);
+ } catch (IOException $exception) {
+ $this->io->writeln('Failed to save file in ' . $target . '');
+ }
+ }
+
+ protected function getNamespace(): string
+ {
+ return (string)key((array)($this->package->getValueFromComposerManifest('autoload')->{'psr-4'} ?? []));
+ }
+
+ private function enhanceComposerFile(array &$composer, array &$addToComposerFile): array
+ {
+ foreach ($addToComposerFile as $key => $value) {
+ if (is_array($value) && isset($composer[$key])) {
+ $this->enhanceComposerFile($composer[$key], $value);
+ } else {
+ $composer[$key] = $value;
+ }
+ }
+
+ return $composer;
+ }
+}
diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml
index fafe6ed..15bf9fa 100644
--- a/Configuration/Services.yaml
+++ b/Configuration/Services.yaml
@@ -51,3 +51,9 @@ services:
command: 'make:testing:setup'
description: 'Create a docker based testing environment setup'
schedulable: false
+ B13\Make\Command\AcceptanceTestsCommand:
+ tags:
+ - name: 'console.command'
+ command: 'make:testing:acceptance'
+ description: 'Create files required to run acceptance tests'
+ schedulable: false
diff --git a/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Application.suite.yml b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Application.suite.yml
new file mode 100644
index 0000000..810a6cd
--- /dev/null
+++ b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Application.suite.yml
@@ -0,0 +1,23 @@
+class_name: ApplicationTester
+modules:
+ enabled:
+ - WebDriver:
+ url: http://web:8000/typo3temp/var/tests/acceptance
+ browser: chrome
+ wait: 1
+ host: chrome
+ window_size: 1400x800
+ - \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:
+ - {{NAMESPACE}}\Tests\Acceptance\Support\Extension\ExtensionEnvironment
+
+groups:
+ AcceptanceTests-Job-*: AcceptanceTests-Job-*
diff --git a/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Application/ExampleCest.php b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Application/ExampleCest.php
new file mode 100644
index 0000000..5af86a6
--- /dev/null
+++ b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Application/ExampleCest.php
@@ -0,0 +1,30 @@
+useExistingSession('admin');
+ $I->switchToMainFrame();
+ }
+
+ /**
+ * @param ApplicationTester $I
+ * @throws \Exception
+ */
+ public function seeTestExample(ApplicationTester $I): void
+ {
+ $I->click('Page');
+ $I->switchToContentFrame();
+ $I->see('Web>Page module', '.callout-info');
+ }
+}
diff --git a/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Fixtures/be_sessions.xml b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Fixtures/be_sessions.xml
new file mode 100644
index 0000000..4160903
--- /dev/null
+++ b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Fixtures/be_sessions.xml
@@ -0,0 +1,19 @@
+
+
+
+
+ 9869d429fc72742a476d5073d006d45dfb732962d9c024423efafef537e1c5bd
+ [DISABLED]
+ 1
+ 1777777777
+
+
+
+
+ f4c02f70058e79a8e7b523a266d4291007deacba6b2ca2536dd72d2fbb23696a
+ [DISABLED]
+ 2
+ 1777777777
+
+
+
diff --git a/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Fixtures/pages.xml b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Fixtures/pages.xml
new file mode 100644
index 0000000..43a50f7
--- /dev/null
+++ b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Fixtures/pages.xml
@@ -0,0 +1,24 @@
+
+
+
+
+ 1
+ 0
+ Home
+
+ 1
+ 0
+ 1
+ 15
+
+
+ 2
+ 1
+ 128
+ Subpage
+ subpage
+ 0
+ 1
+ 15
+
+
diff --git a/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Fixtures/sys_template.xml b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Fixtures/sys_template.xml
new file mode 100644
index 0000000..7d9b169
--- /dev/null
+++ b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Fixtures/sys_template.xml
@@ -0,0 +1,16 @@
+
+
+
+ 1
+ 1
+ Root Template
+ 0
+ 1
+ 3
+
+page = PAGE
+page.10 = TEXT
+page.10.data = page:title
+
+
+
diff --git a/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Support/ApplicationTester.php b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Support/ApplicationTester.php
new file mode 100644
index 0000000..2704bd8
--- /dev/null
+++ b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Support/ApplicationTester.php
@@ -0,0 +1,17 @@
+ [
+ 'core',
+ 'extbase',
+ 'filelist',
+ 'setup',
+ 'frontend',
+ 'fluid',
+ 'recordlist',
+ 'backend',
+ 'install',
+ ],
+ 'testExtensionsToLoad' => [
+ 'typo3conf/ext/{{EXTENSION_KEY}}',
+ ],
+ 'xmlDatabaseFixtures' => [
+ 'PACKAGE:typo3/testing-framework/Resources/Core/Acceptance/Fixtures/be_users.xml',
+ 'PACKAGE:../Web/typo3conf/ext/{{EXTENSION_KEY}}/Tests/Acceptance/Fixtures/pages.xml',
+ 'PACKAGE:../Web/typo3conf/ext/{{EXTENSION_KEY}}/Tests/Acceptance/Fixtures/be_sessions.xml',
+ 'PACKAGE:../Web/typo3conf/ext/{{EXTENSION_KEY}}/Tests/Acceptance/Fixtures/sys_template.xml',
+ ],
+ 'configurationToUseInTestInstance' => [
+ 'MAIL' => [
+ 'transport' => NullTransport::class,
+ ],
+ ],
+
+ // Link files/folders required for your acceptance tests to run
+ // 'pathsToLinkInTestInstance' => [
+ // 'typo3conf/ext/{{EXTENSION_KEY}}/Tests/Acceptance/Fixtures/sites' => 'typo3conf/sites',
+ // ]
+ ];
+}
diff --git a/Resources/Private/CodeTemplates/AcceptanceTests/codeception.yml b/Resources/Private/CodeTemplates/AcceptanceTests/codeception.yml
new file mode 100644
index 0000000..6509bba
--- /dev/null
+++ b/Resources/Private/CodeTemplates/AcceptanceTests/codeception.yml
@@ -0,0 +1,13 @@
+namespace: {{NAMESPACE}}\Tests\Acceptance\Support
+paths:
+ tests: Acceptance
+ data: .
+ log: ../.Build/Web/typo3temp/var/tests/AcceptanceReports
+ support: Acceptance/Support
+settings:
+ colors: true
+ memory_limit: 1024M
+extensions:
+ enabled:
+ - Codeception\Extension\RunFailed
+ - Codeception\Extension\Recorder