From ed9714a77885e305cd5609cf00021f5234816bee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Skowro=C5=84ski?= Date: Wed, 10 Jan 2024 21:21:21 +0100 Subject: [PATCH 01/17] Add Codeception with extra modules --- codeception.yml | 13 + composer.json | 5 + composer.lock | 918 ++++++++++++++++++++++++++- symfony.lock | 27 + tests/_data/.gitignore | 0 tests/_output/.gitignore | 2 + tests/_support/AcceptanceTester.php | 26 + tests/_support/FunctionalTester.php | 26 + tests/_support/Helper/Acceptance.php | 10 + tests/_support/Helper/Functional.php | 10 + tests/_support/Helper/Unit.php | 10 + tests/_support/UnitTester.php | 26 + tests/_support/_generated/.gitignore | 2 + tests/acceptance.suite.yml | 12 + tests/acceptance/.gitignore | 0 tests/functional.suite.yml | 17 + tests/functional/.gitignore | 0 tests/unit.suite.yml | 9 + tests/unit/.gitignore | 0 19 files changed, 1112 insertions(+), 1 deletion(-) create mode 100644 codeception.yml create mode 100644 tests/_data/.gitignore create mode 100644 tests/_output/.gitignore create mode 100644 tests/_support/AcceptanceTester.php create mode 100644 tests/_support/FunctionalTester.php create mode 100644 tests/_support/Helper/Acceptance.php create mode 100644 tests/_support/Helper/Functional.php create mode 100644 tests/_support/Helper/Unit.php create mode 100644 tests/_support/UnitTester.php create mode 100644 tests/_support/_generated/.gitignore create mode 100644 tests/acceptance.suite.yml create mode 100644 tests/acceptance/.gitignore create mode 100644 tests/functional.suite.yml create mode 100644 tests/functional/.gitignore create mode 100644 tests/unit.suite.yml create mode 100644 tests/unit/.gitignore diff --git a/codeception.yml b/codeception.yml new file mode 100644 index 00000000..3007d95c --- /dev/null +++ b/codeception.yml @@ -0,0 +1,13 @@ +namespace: App\Tests +paths: + tests: tests + output: tests/_output + data: tests/_data + support: tests/_support + envs: tests/_envs +actor_suffix: Tester +extensions: + enabled: + - Codeception\Extension\RunFailed +params: + - .env diff --git a/composer.json b/composer.json index 909d5351..8cb260f3 100644 --- a/composer.json +++ b/composer.json @@ -58,6 +58,11 @@ "wohali/oauth2-discord-new": "^1.2" }, "require-dev": { + "codeception/codeception": "^5.0", + "codeception/module-asserts": "^3.0", + "codeception/module-doctrine2": "^3.0", + "codeception/module-rest": "^3.3", + "codeception/module-symfony": "^3.2", "dama/doctrine-test-bundle": "^7.2", "friendsofphp/php-cs-fixer": "^3.23", "phpstan/phpstan": "^1.10", diff --git a/composer.lock b/composer.lock index 8cb4b16c..9338f923 100644 --- a/composer.lock +++ b/composer.lock @@ -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": "89cbc38f43b0b4e9563b4dc544d92488", + "content-hash": "b51c778d94f5639fa4471a508ddc6886", "packages": [ { "name": "api-platform/core", @@ -9998,6 +9998,705 @@ } ], "packages-dev": [ + { + "name": "behat/gherkin", + "version": "v4.9.0", + "source": { + "type": "git", + "url": "https://github.com/Behat/Gherkin.git", + "reference": "0bc8d1e30e96183e4f36db9dc79caead300beff4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/0bc8d1e30e96183e4f36db9dc79caead300beff4", + "reference": "0bc8d1e30e96183e4f36db9dc79caead300beff4", + "shasum": "" + }, + "require": { + "php": "~7.2|~8.0" + }, + "require-dev": { + "cucumber/cucumber": "dev-gherkin-22.0.0", + "phpunit/phpunit": "~8|~9", + "symfony/yaml": "~3|~4|~5" + }, + "suggest": { + "symfony/yaml": "If you want to parse features, represented in YAML files" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev" + } + }, + "autoload": { + "psr-0": { + "Behat\\Gherkin": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + } + ], + "description": "Gherkin DSL parser for PHP", + "homepage": "http://behat.org/", + "keywords": [ + "BDD", + "Behat", + "Cucumber", + "DSL", + "gherkin", + "parser" + ], + "support": { + "issues": "https://github.com/Behat/Gherkin/issues", + "source": "https://github.com/Behat/Gherkin/tree/v4.9.0" + }, + "time": "2021-10-12T13:05:09+00:00" + }, + { + "name": "codeception/codeception", + "version": "5.0.13", + "source": { + "type": "git", + "url": "https://github.com/Codeception/Codeception.git", + "reference": "713a90195efa2926566e24bfc623da703ff42bba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/713a90195efa2926566e24bfc623da703ff42bba", + "reference": "713a90195efa2926566e24bfc623da703ff42bba", + "shasum": "" + }, + "require": { + "behat/gherkin": "^4.6.2", + "codeception/lib-asserts": "^2.0", + "codeception/stub": "^4.1", + "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "php": "^8.0", + "phpunit/php-code-coverage": "^9.2 || ^10.0", + "phpunit/php-text-template": "^2.0 || ^3.0", + "phpunit/php-timer": "^5.0.3 || ^6.0", + "phpunit/phpunit": "^9.5.20 || ^10.0", + "psy/psysh": "^0.11.2 || ^0.12", + "sebastian/comparator": "^4.0.5 || ^5.0", + "sebastian/diff": "^4.0.3 || ^5.0", + "symfony/console": ">=4.4.24 <8.0", + "symfony/css-selector": ">=4.4.24 <8.0", + "symfony/event-dispatcher": ">=4.4.24 <8.0", + "symfony/finder": ">=4.4.24 <8.0", + "symfony/var-dumper": ">=4.4.24 <8.0", + "symfony/yaml": ">=4.4.24 <8.0" + }, + "conflict": { + "codeception/lib-innerbrowser": "<3.1.3", + "codeception/module-filesystem": "<3.0", + "codeception/module-phpbrowser": "<2.5" + }, + "replace": { + "codeception/phpunit-wrapper": "*" + }, + "require-dev": { + "codeception/lib-innerbrowser": "*@dev", + "codeception/lib-web": "^1.0", + "codeception/module-asserts": "*@dev", + "codeception/module-cli": "*@dev", + "codeception/module-db": "*@dev", + "codeception/module-filesystem": "*@dev", + "codeception/module-phpbrowser": "*@dev", + "codeception/util-universalframework": "*@dev", + "ext-simplexml": "*", + "jetbrains/phpstorm-attributes": "^1.0", + "symfony/dotenv": ">=4.4.24 <8.0", + "symfony/process": ">=4.4.24 <8.0", + "vlucas/phpdotenv": "^5.1" + }, + "suggest": { + "codeception/specify": "BDD-style code blocks", + "codeception/verify": "BDD-style assertions", + "ext-simplexml": "For loading params from XML files", + "stecman/symfony-console-completion": "For BASH autocompletion", + "symfony/dotenv": "For loading params from .env files", + "symfony/phpunit-bridge": "For phpunit-bridge support", + "vlucas/phpdotenv": "For loading params from .env files" + }, + "bin": [ + "codecept" + ], + "type": "library", + "autoload": { + "files": [ + "functions.php" + ], + "psr-4": { + "Codeception\\": "src/Codeception", + "Codeception\\Extension\\": "ext" + }, + "classmap": [ + "src/PHPUnit/TestCase.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk", + "email": "davert.ua@gmail.com", + "homepage": "https://codeception.com" + } + ], + "description": "BDD-style testing framework", + "homepage": "https://codeception.com/", + "keywords": [ + "BDD", + "TDD", + "acceptance testing", + "functional testing", + "unit testing" + ], + "support": { + "issues": "https://github.com/Codeception/Codeception/issues", + "source": "https://github.com/Codeception/Codeception/tree/5.0.13" + }, + "funding": [ + { + "url": "https://opencollective.com/codeception", + "type": "open_collective" + } + ], + "time": "2023-12-22T19:32:40+00:00" + }, + { + "name": "codeception/lib-asserts", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/Codeception/lib-asserts.git", + "reference": "b8c7dff552249e560879c682ba44a4b963af91bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/lib-asserts/zipball/b8c7dff552249e560879c682ba44a4b963af91bc", + "reference": "b8c7dff552249e560879c682ba44a4b963af91bc", + "shasum": "" + }, + "require": { + "codeception/phpunit-wrapper": "^7.7.1 | ^8.0.3 | ^9.0", + "ext-dom": "*", + "php": "^7.4 | ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk", + "email": "davert@mail.ua", + "homepage": "http://codegyre.com" + }, + { + "name": "Gintautas Miselis" + }, + { + "name": "Gustavo Nieves", + "homepage": "https://medium.com/@ganieves" + } + ], + "description": "Assertion methods used by Codeception core and Asserts module", + "homepage": "https://codeception.com/", + "keywords": [ + "codeception" + ], + "support": { + "issues": "https://github.com/Codeception/lib-asserts/issues", + "source": "https://github.com/Codeception/lib-asserts/tree/2.1.0" + }, + "time": "2023-02-10T18:36:23+00:00" + }, + { + "name": "codeception/lib-innerbrowser", + "version": "3.1.3", + "source": { + "type": "git", + "url": "https://github.com/Codeception/lib-innerbrowser.git", + "reference": "10482f7e34c0537bf5b87bc82a3d65a1842a8b4f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/lib-innerbrowser/zipball/10482f7e34c0537bf5b87bc82a3d65a1842a8b4f", + "reference": "10482f7e34c0537bf5b87bc82a3d65a1842a8b4f", + "shasum": "" + }, + "require": { + "codeception/codeception": "^5.0", + "codeception/lib-web": "^1.0.1", + "ext-dom": "*", + "ext-json": "*", + "ext-mbstring": "*", + "php": "^8.0", + "phpunit/phpunit": "^9.5", + "symfony/browser-kit": "^4.4.24 || ^5.4 || ^6.0", + "symfony/dom-crawler": "^4.4.30 || ^5.4 || ^6.0" + }, + "require-dev": { + "codeception/util-universalframework": "dev-master" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk", + "email": "davert@mail.ua", + "homepage": "https://codegyre.com" + }, + { + "name": "Gintautas Miselis" + } + ], + "description": "Parent library for all Codeception framework modules and PhpBrowser", + "homepage": "https://codeception.com/", + "keywords": [ + "codeception" + ], + "support": { + "issues": "https://github.com/Codeception/lib-innerbrowser/issues", + "source": "https://github.com/Codeception/lib-innerbrowser/tree/3.1.3" + }, + "time": "2022-10-03T15:33:34+00:00" + }, + { + "name": "codeception/lib-web", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/Codeception/lib-web.git", + "reference": "28cb2ed1169de18e720bec758015aadc37d8344c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/lib-web/zipball/28cb2ed1169de18e720bec758015aadc37d8344c", + "reference": "28cb2ed1169de18e720bec758015aadc37d8344c", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "guzzlehttp/psr7": "^2.0", + "php": "^8.0", + "symfony/css-selector": ">=4.4.24 <8.0" + }, + "conflict": { + "codeception/codeception": "<5.0.0-alpha3" + }, + "require-dev": { + "php-webdriver/webdriver": "^1.12", + "phpunit/phpunit": "^9.5 | ^10.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gintautas Miselis" + } + ], + "description": "Library containing files used by module-webdriver and lib-innerbrowser or module-phpbrowser", + "homepage": "https://codeception.com/", + "keywords": [ + "codeception" + ], + "support": { + "issues": "https://github.com/Codeception/lib-web/issues", + "source": "https://github.com/Codeception/lib-web/tree/1.0.4" + }, + "time": "2023-12-01T11:38:22+00:00" + }, + { + "name": "codeception/lib-xml", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/Codeception/lib-xml.git", + "reference": "4eabf029ff5e40c7e8a16b6db2fe9bbb9244d162" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/lib-xml/zipball/4eabf029ff5e40c7e8a16b6db2fe9bbb9244d162", + "reference": "4eabf029ff5e40c7e8a16b6db2fe9bbb9244d162", + "shasum": "" + }, + "require": { + "codeception/lib-web": "^1.0", + "ext-dom": "*", + "php": "^8.0", + "phpunit/phpunit": "^9.5 | ^10.0", + "symfony/css-selector": ">=4.4.24 <8.0" + }, + "conflict": { + "codeception/codeception": "<5.0.0-alpha3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gintautas Miselis" + } + ], + "description": "Files used by module-rest and module-soap", + "homepage": "https://codeception.com/", + "keywords": [ + "codeception" + ], + "support": { + "issues": "https://github.com/Codeception/lib-xml/issues", + "source": "https://github.com/Codeception/lib-xml/tree/1.0.2" + }, + "time": "2023-12-08T19:31:41+00:00" + }, + { + "name": "codeception/module-asserts", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/Codeception/module-asserts.git", + "reference": "1b6b150b30586c3614e7e5761b31834ed7968603" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/module-asserts/zipball/1b6b150b30586c3614e7e5761b31834ed7968603", + "reference": "1b6b150b30586c3614e7e5761b31834ed7968603", + "shasum": "" + }, + "require": { + "codeception/codeception": "*@dev", + "codeception/lib-asserts": "^2.0", + "php": "^8.0" + }, + "conflict": { + "codeception/codeception": "<5.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk" + }, + { + "name": "Gintautas Miselis" + }, + { + "name": "Gustavo Nieves", + "homepage": "https://medium.com/@ganieves" + } + ], + "description": "Codeception module containing various assertions", + "homepage": "https://codeception.com/", + "keywords": [ + "assertions", + "asserts", + "codeception" + ], + "support": { + "issues": "https://github.com/Codeception/module-asserts/issues", + "source": "https://github.com/Codeception/module-asserts/tree/3.0.0" + }, + "time": "2022-02-16T19:48:08+00:00" + }, + { + "name": "codeception/module-doctrine2", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/Codeception/module-doctrine2.git", + "reference": "3ba1c67fc15a0fe9dcf594746e81a876c667daf1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/module-doctrine2/zipball/3ba1c67fc15a0fe9dcf594746e81a876c667daf1", + "reference": "3ba1c67fc15a0fe9dcf594746e81a876c667daf1", + "shasum": "" + }, + "require": { + "codeception/codeception": "^5.0.0-alpha2", + "ext-json": "*", + "ext-pdo": "*", + "php": "^8.0" + }, + "conflict": { + "codeception/codeception": "<5.0" + }, + "require-dev": { + "codeception/stub": "^4.0", + "doctrine/annotations": "^1.13", + "doctrine/data-fixtures": "^1.5", + "doctrine/orm": "^2.10", + "phpstan/phpstan": "^1.0", + "ramsey/uuid-doctrine": "^1.6", + "symfony/cache": "^4.4 || ^5.4 || ^6.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk" + }, + { + "name": "Alex Kunin" + } + ], + "description": "Doctrine2 module for Codeception", + "homepage": "https://codeception.com/", + "keywords": [ + "codeception", + "doctrine2" + ], + "support": { + "issues": "https://github.com/Codeception/module-doctrine2/issues", + "source": "https://github.com/Codeception/module-doctrine2/tree/3.0.3" + }, + "time": "2023-04-18T19:35:17+00:00" + }, + { + "name": "codeception/module-rest", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/Codeception/module-rest.git", + "reference": "bb545d4f7c261472472da8730267d9df162199cb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/module-rest/zipball/bb545d4f7c261472472da8730267d9df162199cb", + "reference": "bb545d4f7c261472472da8730267d9df162199cb", + "shasum": "" + }, + "require": { + "codeception/codeception": "^5.0.8", + "codeception/lib-xml": "^1.0", + "ext-dom": "*", + "ext-json": "*", + "justinrainbow/json-schema": "~5.2.9", + "php": "^8.0", + "softcreatr/jsonpath": "^0.8" + }, + "require-dev": { + "codeception/lib-innerbrowser": "^3.0 | ^4.0", + "codeception/stub": "^4.0", + "codeception/util-universalframework": "^1.0", + "ext-libxml": "*", + "ext-simplexml": "*" + }, + "suggest": { + "aws/aws-sdk-php": "For using AWS Auth" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gintautas Miselis" + } + ], + "description": "REST module for Codeception", + "homepage": "https://codeception.com/", + "keywords": [ + "codeception", + "rest" + ], + "support": { + "issues": "https://github.com/Codeception/module-rest/issues", + "source": "https://github.com/Codeception/module-rest/tree/3.3.2" + }, + "time": "2023-02-09T18:11:19+00:00" + }, + { + "name": "codeception/module-symfony", + "version": "3.2.0", + "source": { + "type": "git", + "url": "https://github.com/Codeception/module-symfony.git", + "reference": "5798e3e6328d20e9c41a5d1680f245e9881a4a43" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/module-symfony/zipball/5798e3e6328d20e9c41a5d1680f245e9881a4a43", + "reference": "5798e3e6328d20e9c41a5d1680f245e9881a4a43", + "shasum": "" + }, + "require": { + "codeception/codeception": "^5.0.8", + "codeception/lib-innerbrowser": "^3.1.1 | ^4.0", + "ext-json": "*", + "php": "^8.0" + }, + "require-dev": { + "codeception/module-asserts": "^3.0", + "codeception/module-doctrine2": "^3.0", + "doctrine/orm": "^2.10", + "symfony/browser-kit": "^4.4 | ^5.0 | ^6.0", + "symfony/cache": "^4.4 | ^5.0 | ^6.0", + "symfony/config": "^4.4 | ^5.0 | ^6.0", + "symfony/dependency-injection": "^4.4 | ^5.0 | ^6.0", + "symfony/dom-crawler": "^4.4 | ^5.0 | ^6.0", + "symfony/error-handler": "^4.4 | ^5.0 | ^6.0", + "symfony/filesystem": "^4.4 | ^5.0 | ^6.0", + "symfony/form": "^4.4 | ^5.0 | ^6.0", + "symfony/framework-bundle": "^4.4 | ^5.0 | ^6.0", + "symfony/http-foundation": "^4.4 | ^5.0 | ^6.0", + "symfony/http-kernel": "^4.4 | ^5.0 | ^6.0", + "symfony/mailer": "^4.4 | ^5.0 | ^6.0", + "symfony/mime": "^4.4 | ^5.0 | ^6.0", + "symfony/options-resolver": "^4.4 | ^5.0 | ^6.0", + "symfony/property-access": "^4.4 | ^5.0 | ^6.0", + "symfony/property-info": "^4.4 | ^5.0 | ^6.0", + "symfony/routing": "^4.4 | ^5.0 | ^6.0", + "symfony/security-bundle": "^4.4 | ^5.0 | ^6.0", + "symfony/security-core": "^4.4 | ^5.0 | ^6.0", + "symfony/security-csrf": "^4.4 | ^5.0 | ^6.0", + "symfony/security-http": "^4.4 | ^5.0 | ^6.0", + "symfony/twig-bundle": "^4.4 | ^5.0 | ^6.0", + "symfony/var-exporter": "^4.4 | ^5.0 | ^6.0", + "vlucas/phpdotenv": "^4.2 | ^5.4" + }, + "suggest": { + "codeception/module-asserts": "Include traditional PHPUnit assertions in your tests", + "symfony/web-profiler-bundle": "Tool that gives information about the execution of requests" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk" + }, + { + "name": "Gustavo Nieves", + "homepage": "https://medium.com/@ganieves" + } + ], + "description": "Codeception module for Symfony framework", + "homepage": "https://codeception.com/", + "keywords": [ + "codeception", + "symfony" + ], + "support": { + "issues": "https://github.com/Codeception/module-symfony/issues", + "source": "https://github.com/Codeception/module-symfony/tree/3.2.0" + }, + "time": "2024-01-02T03:05:57+00:00" + }, + { + "name": "codeception/stub", + "version": "4.1.2", + "source": { + "type": "git", + "url": "https://github.com/Codeception/Stub.git", + "reference": "f6bc56e33e3f5ba7a831dfb968c49b27cf1676ad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/Stub/zipball/f6bc56e33e3f5ba7a831dfb968c49b27cf1676ad", + "reference": "f6bc56e33e3f5ba7a831dfb968c49b27cf1676ad", + "shasum": "" + }, + "require": { + "php": "^7.4 | ^8.0", + "phpunit/phpunit": "^8.4 | ^9.0 | ^10.0 | 10.0.x-dev" + }, + "conflict": { + "codeception/codeception": "<5.0.6" + }, + "require-dev": { + "consolidation/robo": "^3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Codeception\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Flexible Stub wrapper for PHPUnit's Mock Builder", + "support": { + "issues": "https://github.com/Codeception/Stub/issues", + "source": "https://github.com/Codeception/Stub/tree/4.1.2" + }, + "time": "2023-10-07T19:22:36+00:00" + }, { "name": "composer/pcre", "version": "3.1.0", @@ -10456,6 +11155,76 @@ ], "time": "2023-08-14T12:27:35+00:00" }, + { + "name": "justinrainbow/json-schema", + "version": "v5.2.13", + "source": { + "type": "git", + "url": "https://github.com/justinrainbow/json-schema.git", + "reference": "fbbe7e5d79f618997bc3332a6f49246036c45793" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/fbbe7e5d79f618997bc3332a6f49246036c45793", + "reference": "fbbe7e5d79f618997bc3332a6f49246036c45793", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", + "json-schema/json-schema-test-suite": "1.2.0", + "phpunit/phpunit": "^4.8.35" + }, + "bin": [ + "bin/validate-json" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "JsonSchema\\": "src/JsonSchema/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bruno Prieto Reis", + "email": "bruno.p.reis@gmail.com" + }, + { + "name": "Justin Rainbow", + "email": "justin.rainbow@gmail.com" + }, + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + }, + { + "name": "Robert Schönthal", + "email": "seroscho@googlemail.com" + } + ], + "description": "A library to validate a json schema.", + "homepage": "https://github.com/justinrainbow/json-schema", + "keywords": [ + "json", + "schema" + ], + "support": { + "issues": "https://github.com/justinrainbow/json-schema/issues", + "source": "https://github.com/justinrainbow/json-schema/tree/v5.2.13" + }, + "time": "2023-09-26T02:20:38+00:00" + }, { "name": "masterminds/html5", "version": "2.8.1", @@ -11474,6 +12243,85 @@ ], "time": "2023-07-10T04:04:23+00:00" }, + { + "name": "psy/psysh", + "version": "v0.12.0", + "source": { + "type": "git", + "url": "https://github.com/bobthecow/psysh.git", + "reference": "750bf031a48fd07c673dbe3f11f72362ea306d0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/750bf031a48fd07c673dbe3f11f72362ea306d0d", + "reference": "750bf031a48fd07c673dbe3f11f72362ea306d0d", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-tokenizer": "*", + "nikic/php-parser": "^5.0 || ^4.0", + "php": "^8.0 || ^7.4", + "symfony/console": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4", + "symfony/var-dumper": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4" + }, + "conflict": { + "symfony/console": "4.4.37 || 5.3.14 || 5.3.15 || 5.4.3 || 5.4.4 || 6.0.3 || 6.0.4" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.2" + }, + "suggest": { + "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", + "ext-pdo-sqlite": "The doc command requires SQLite to work.", + "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well." + }, + "bin": [ + "bin/psysh" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "0.12.x-dev" + }, + "bamarni-bin": { + "bin-links": false, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Psy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Justin Hileman", + "email": "justin@justinhileman.info", + "homepage": "http://justinhileman.com" + } + ], + "description": "An interactive shell for modern PHP.", + "homepage": "http://psysh.org", + "keywords": [ + "REPL", + "console", + "interactive", + "shell" + ], + "support": { + "issues": "https://github.com/bobthecow/psysh/issues", + "source": "https://github.com/bobthecow/psysh/tree/v0.12.0" + }, + "time": "2023-12-20T15:28:09+00:00" + }, { "name": "roave/security-advisories", "version": "dev-latest", @@ -13098,6 +13946,74 @@ ], "time": "2020-09-28T06:39:44+00:00" }, + { + "name": "softcreatr/jsonpath", + "version": "0.8.3", + "source": { + "type": "git", + "url": "https://github.com/SoftCreatR/JSONPath.git", + "reference": "fc12dee0b46f3fa3a175c4051dbab60984acef4b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/SoftCreatR/JSONPath/zipball/fc12dee0b46f3fa3a175c4051dbab60984acef4b", + "reference": "fc12dee0b46f3fa3a175c4051dbab60984acef4b", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=8.0" + }, + "replace": { + "flow/jsonpath": "*" + }, + "require-dev": { + "phpunit/phpunit": "^9.6", + "roave/security-advisories": "dev-latest" + }, + "type": "library", + "autoload": { + "psr-4": { + "Flow\\JSONPath\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Stephen Frank", + "email": "stephen@flowsa.com", + "homepage": "https://prismaticbytes.com", + "role": "Developer" + }, + { + "name": "Sascha Greuel", + "email": "hello@1-2.dev", + "homepage": "https://1-2.dev", + "role": "Developer" + } + ], + "description": "JSONPath implementation for parsing, searching and flattening arrays", + "support": { + "email": "hello@1-2.dev", + "forum": "https://github.com/SoftCreatR/JSONPath/discussions", + "issues": "https://github.com/SoftCreatR/JSONPath/issues", + "source": "https://github.com/SoftCreatR/JSONPath" + }, + "funding": [ + { + "url": "https://ecologi.com/softcreatr?r=61212ab3fc69b8eb8a2014f4", + "type": "custom" + }, + { + "url": "https://github.com/softcreatr", + "type": "github" + } + ], + "time": "2023-08-17T20:14:00+00:00" + }, { "name": "symfony/browser-kit", "version": "v6.4.0", diff --git a/symfony.lock b/symfony.lock index 66ab6544..d13eff0d 100644 --- a/symfony.lock +++ b/symfony.lock @@ -13,6 +13,33 @@ "src/Entity/.gitignore" ] }, + "codeception/codeception": { + "version": "5.0", + "recipe": { + "repo": "github.com/symfony/recipes-contrib", + "branch": "main", + "version": "2.3", + "ref": "89689e24507d8cb2c4a7937ece549db3836b608c" + }, + "files": [ + "codeception.yml", + "tests/_data/.gitignore", + "tests/_output/.gitignore", + "tests/_support/AcceptanceTester.php", + "tests/_support/FunctionalTester.php", + "tests/_support/Helper/Acceptance.php", + "tests/_support/Helper/Functional.php", + "tests/_support/Helper/Unit.php", + "tests/_support/UnitTester.php", + "tests/_support/_generated/.gitignore", + "tests/acceptance.suite.yml", + "tests/acceptance/.gitignore", + "tests/functional.suite.yml", + "tests/functional/.gitignore", + "tests/unit.suite.yml", + "tests/unit/.gitignore" + ] + }, "dama/doctrine-test-bundle": { "version": "7.2", "recipe": { diff --git a/tests/_data/.gitignore b/tests/_data/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/tests/_output/.gitignore b/tests/_output/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/tests/_output/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/tests/_support/AcceptanceTester.php b/tests/_support/AcceptanceTester.php new file mode 100644 index 00000000..e0b036bc --- /dev/null +++ b/tests/_support/AcceptanceTester.php @@ -0,0 +1,26 @@ + Date: Mon, 28 Aug 2023 20:51:40 +0200 Subject: [PATCH 02/17] Add Codeception config --- .github/workflows/application.yml | 6 +-- .php-cs-fixer.dist.php | 15 +++--- Makefile | 17 ++++--- codeception.yml | 1 + composer.json | 1 + config/packages/framework.yaml | 1 - .../test/dama_doctrine_test_bundle.yaml | 4 -- config/packages/web_profiler.yaml | 2 +- docker-compose.test.yml | 4 +- phpstan.neon.dist | 2 + phpunit.xml.dist | 47 ------------------- tests/_support/AcceptanceTester.php | 26 ---------- tests/_support/FunctionalTester.php | 38 ++++++++------- tests/_support/Helper/Acceptance.php | 10 ---- tests/_support/Helper/Functional.php | 4 +- tests/_support/Helper/Unit.php | 10 ---- tests/_support/IntegrationTester.php | 32 +++++++++++++ tests/_support/UnitTester.php | 38 ++++++++------- tests/acceptance.suite.yml | 12 ----- tests/functional.suite.yml | 27 +++++------ tests/integration.suite.yml | 10 ++++ tests/{acceptance => integration}/.gitignore | 0 tests/unit.suite.yml | 5 -- 23 files changed, 131 insertions(+), 181 deletions(-) delete mode 100644 config/packages/test/dama_doctrine_test_bundle.yaml delete mode 100644 phpunit.xml.dist delete mode 100644 tests/_support/AcceptanceTester.php delete mode 100644 tests/_support/Helper/Acceptance.php delete mode 100644 tests/_support/Helper/Unit.php create mode 100644 tests/_support/IntegrationTester.php delete mode 100644 tests/acceptance.suite.yml create mode 100644 tests/integration.suite.yml rename tests/{acceptance => integration}/.gitignore (100%) diff --git a/.github/workflows/application.yml b/.github/workflows/application.yml index be634808..3f21416c 100644 --- a/.github/workflows/application.yml +++ b/.github/workflows/application.yml @@ -29,9 +29,9 @@ jobs: docker compose -f docker-compose.test.yml up --wait docker compose exec -T php composer install - - name: Setup database + - name: Setup tests run: | - make db env=test + make test-setup - name: Run lint run: | @@ -40,7 +40,7 @@ jobs: - name: Run tests run: | - make test-ci + make test - name: Failure logs if: failure() diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 77cd1df4..4830cd05 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -3,6 +3,7 @@ declare(strict_types=1); $finder = PhpCsFixer\Finder::create() + ->in(__DIR__) ->exclude('var') ->exclude('node_modules') ->notPath('config/bundles.php') @@ -11,7 +12,11 @@ ->notPath('public/index.php') ->notPath('src/Kernel.php') ->notPath('tests/bootstrap.php') - ->in(__DIR__) + + # Codeception + ->exclude('tests/_data') + ->exclude('tests/_output') + ->exclude('tests/_support/_generated') ; return (new PhpCsFixer\Config()) @@ -26,12 +31,11 @@ '@PHP80Migration' => true, '@PHP80Migration:risky' => true, - 'php_unit_test_annotation' => [ - 'style' => 'annotation', - ], + 'php_unit_internal_class' => false, 'php_unit_method_casing' => false, + 'php_unit_test_class_requires_covers' => false, + 'phpdoc_separation' => false, 'phpdoc_to_comment' => false, - 'ordered_traits' => false, 'ordered_class_elements' => [ 'order' => [ 'use_trait', // traits @@ -64,7 +68,6 @@ ], 'sort_algorithm' => 'none', ], - 'phpdoc_separation' => false ]) ->setFinder($finder) ; diff --git a/Makefile b/Makefile index c860a30f..0f12ed76 100644 --- a/Makefile +++ b/Makefile @@ -23,15 +23,18 @@ db: docker-compose exec -T php php bin/console doctrine:database:create --if-not-exists --env=${env} docker-compose exec -T php php bin/console doctrine:migration:migrate --no-interaction --env=${env} + docker-compose exec -T php php bin/console doctrine:fixtures:load --no-interaction --env=${env} + +console: + @docker-compose exec php sh + setup: @make db - docker-compose exec -T php php bin/console app:import:modlists var/import -test: +test-setup: @make db env=test - @make test-ci + docker-compose exec -T php php vendor/bin/codecept clean + docker-compose exec -T php php vendor/bin/codecept build -test-ci: - docker-compose exec -T php php bin/console doctrine:fixtures:load --no-interaction --env=test - - docker-compose exec -T php php bin/phpunit --testdox +test: + docker-compose exec -T php php vendor/bin/codecept run unit,integration,functional --fail-fast diff --git a/codeception.yml b/codeception.yml index 3007d95c..c9312c1a 100644 --- a/codeception.yml +++ b/codeception.yml @@ -11,3 +11,4 @@ extensions: - Codeception\Extension\RunFailed params: - .env + - .env.test diff --git a/composer.json b/composer.json index 8cb260f3..ef643fb0 100644 --- a/composer.json +++ b/composer.json @@ -95,6 +95,7 @@ }, "autoload-dev": { "psr-4": { + "App\\Tests\\": "tests/_support/", "App\\Tests\\Unit\\": "tests/unit", "App\\Tests\\Integration\\": "tests/integration", "App\\Tests\\Functional\\": "tests/functional" diff --git a/config/packages/framework.yaml b/config/packages/framework.yaml index 077b2875..6fb94e31 100644 --- a/config/packages/framework.yaml +++ b/config/packages/framework.yaml @@ -24,7 +24,6 @@ framework: trusted_proxies: '10.0.0.0/8,172.16.0.0/12,192.168.0.0/16' trusted_headers: [ 'x-forwarded-for', 'x-forwarded-proto', 'x-forwarded-port', 'x-forwarded-host' ] -# This needs to be disabled so tests use regular session storage and to user data providers to work when@test: framework: test: true diff --git a/config/packages/test/dama_doctrine_test_bundle.yaml b/config/packages/test/dama_doctrine_test_bundle.yaml deleted file mode 100644 index 80b00911..00000000 --- a/config/packages/test/dama_doctrine_test_bundle.yaml +++ /dev/null @@ -1,4 +0,0 @@ -dama_doctrine_test: - enable_static_connection: true - enable_static_meta_data_cache: true - enable_static_query_cache: true diff --git a/config/packages/web_profiler.yaml b/config/packages/web_profiler.yaml index b9461110..c987cb68 100644 --- a/config/packages/web_profiler.yaml +++ b/config/packages/web_profiler.yaml @@ -14,4 +14,4 @@ when@test: intercept_redirects: false framework: - profiler: { collect: false } + profiler: { collect: true } # Enabled Profiler is required by Codeception diff --git a/docker-compose.test.yml b/docker-compose.test.yml index 4795010c..5ab13050 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -15,8 +15,8 @@ services: volumes: # Copy tests into runtime - './.env.test:/www/app/.env.test:ro' - - './tests:/www/app/tests:ro' - - './phpunit.xml.dist:/www/app/phpunit.xml.dist:ro' + - './tests:/www/app/tests:rw' + - './codeception.yml:/www/app/codeception.yml' - './.php-cs-fixer.dist.php:/www/app/.php-cs-fixer.dist.php:ro' - './phpstan.neon.dist:/www/app/phpstan.neon.dist:ro' depends_on: diff --git a/phpstan.neon.dist b/phpstan.neon.dist index bd0d663f..6d85e929 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -15,6 +15,8 @@ parameters: paths: - src - tests + excludePaths: + - tests/_support/_generated symfony: container_xml_path: 'var/cache/dev/App_KernelDevDebugContainer.xml' checkGenericClassInNonGenericObjectType: false diff --git a/phpunit.xml.dist b/phpunit.xml.dist deleted file mode 100644 index 0a1cde20..00000000 --- a/phpunit.xml.dist +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - - - - tests/unit - - - tests/integration - - - tests/functional - - - - - - src - - - - - - - - - - - diff --git a/tests/_support/AcceptanceTester.php b/tests/_support/AcceptanceTester.php deleted file mode 100644 index e0b036bc..00000000 --- a/tests/_support/AcceptanceTester.php +++ /dev/null @@ -1,26 +0,0 @@ - Date: Thu, 12 Oct 2023 23:22:31 +0200 Subject: [PATCH 03/17] Update unit tests --- .../SteamApiClient/Helper/SteamHelper.php | 4 +- .../Doctrine/EntityBlamableSubscriberTest.php | 40 ++++-------- .../Discord/DiscordClientFactoryTest.php | 18 ++---- .../Service/Mission/MissionClientTest.php | 11 +--- .../SteamApiClient/Helper/SteamHelperTest.php | 62 +++++++------------ 5 files changed, 42 insertions(+), 93 deletions(-) diff --git a/src/Service/SteamApiClient/Helper/SteamHelper.php b/src/Service/SteamApiClient/Helper/SteamHelper.php index ecca0700..236d73a7 100644 --- a/src/Service/SteamApiClient/Helper/SteamHelper.php +++ b/src/Service/SteamApiClient/Helper/SteamHelper.php @@ -9,8 +9,8 @@ class SteamHelper { - public const ITEM_URL_REGEX = '~^https://steamcommunity\.com/(?:sharedfiles|workshop)/filedetails/\?id=(\d+)$~'; - public const APP_URL_REGEX = '~^https://store\.steampowered\.com/app/(\d+)~'; + private const ITEM_URL_REGEX = '~^https://steamcommunity\.com/(?:sharedfiles|workshop)/filedetails/\?id=(\d+)$~'; + private const APP_URL_REGEX = '~^https://store\.steampowered\.com/app/(\d+)~'; public static function profileIdToProfileUrl(int $profileId): string { diff --git a/tests/unit/EventSubscriber/Doctrine/EntityBlamableSubscriberTest.php b/tests/unit/EventSubscriber/Doctrine/EntityBlamableSubscriberTest.php index 4f1a899d..81690f08 100644 --- a/tests/unit/EventSubscriber/Doctrine/EntityBlamableSubscriberTest.php +++ b/tests/unit/EventSubscriber/Doctrine/EntityBlamableSubscriberTest.php @@ -7,23 +7,17 @@ use App\Entity\AbstractBlamableEntity; use App\Entity\User\User; use App\EventSubscriber\Doctrine\EntityBlamableSubscriber; +use Codeception\Attribute\DataProvider; +use Codeception\Test\Unit; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Event\PrePersistEventArgs; use Doctrine\ORM\Event\PreUpdateEventArgs; use Doctrine\ORM\Events; -use PHPUnit\Framework\TestCase; use Symfony\Bundle\SecurityBundle\Security; -/** - * @internal - * @covers \App\EventSubscriber\Doctrine\EntityBlamableSubscriber - */ -final class EntityBlamableSubscriberTest extends TestCase +final class EntityBlamableSubscriberTest extends Unit { - /** - * @test - */ - public function getSubscribedEvents(): void + public function testGetSubscribedEvents(): void { $security = $this->createMock(Security::class); $entityBlamableSubscriberTest = new EntityBlamableSubscriber($security); @@ -37,10 +31,7 @@ public function getSubscribedEvents(): void self::assertSame($expectedEvents, $subscribedEvents); } - /** - * @test - */ - public function prePersist_validEventArgs_entityUpdated(): void + public function testMarkEntityAsCreated(): void { $user = $this->createMock(User::class); $security = $this->createMock(Security::class); @@ -60,11 +51,8 @@ public function prePersist_validEventArgs_entityUpdated(): void $entityBlamableSubscriberTest->prePersist($lifecycleEventArgs); } - /** - * @test - * @dataProvider invalidEventArgs - */ - public function prePersist_invalidEventArgs_entityNotUpdated(mixed $user, mixed $entity): void + #[DataProvider('invalidEventArgs')] + public function testDoNotMarkEntityAsCreated(mixed $user, mixed $entity): void { $security = $this->createMock(Security::class); $security->method('getUser')->willReturn($user); @@ -76,10 +64,7 @@ public function prePersist_invalidEventArgs_entityNotUpdated(mixed $user, mixed $entityBlamableSubscriberTest->prePersist($lifecycleEventArgs); } - /** - * @test - */ - public function preUpdate_validEventArgs_entityUpdated(): void + public function testMarkEntityAsUpdated(): void { $user = $this->createMock(User::class); $security = $this->createMock(Security::class); @@ -100,11 +85,8 @@ public function preUpdate_validEventArgs_entityUpdated(): void $entityBlamableSubscriberTest->preUpdate($lifecycleEventArgs); } - /** - * @test - * @dataProvider invalidEventArgs - */ - public function preUpdate_invalidEventArgs_entityNotUpdated(mixed $user, mixed $entity): void + #[DataProvider('invalidEventArgs')] + public function testDoNotMarkEntityAsUpdated(mixed $user, mixed $entity): void { $security = $this->createMock(Security::class); $security->method('getUser')->willReturn($user); @@ -118,7 +100,7 @@ public function preUpdate_invalidEventArgs_entityNotUpdated(mixed $user, mixed $ $entityBlamableSubscriberTest->preUpdate($lifecycleEventArgs); } - public function invalidEventArgs(): iterable + protected function invalidEventArgs(): iterable { $validUser = $this->createMock(User::class); $invalidUser = null; diff --git a/tests/unit/Service/Discord/DiscordClientFactoryTest.php b/tests/unit/Service/Discord/DiscordClientFactoryTest.php index fb4dcff3..1e629811 100644 --- a/tests/unit/Service/Discord/DiscordClientFactoryTest.php +++ b/tests/unit/Service/Discord/DiscordClientFactoryTest.php @@ -5,19 +5,12 @@ namespace App\Tests\Unit\Service\Discord; use App\Service\Discord\DiscordClientFactory; -use PHPUnit\Framework\TestCase; +use Codeception\Test\Unit; use Psr\Log\LoggerInterface; -/** - * @internal - * @covers \App\Service\Discord\DiscordClientFactory - */ -final class DiscordClientFactoryTest extends TestCase +final class DiscordClientFactoryTest extends Unit { - /** - * @test - */ - public function createBotClient_validTokenType_returnsValidClient(): void + public function testCreatesBotClient(): void { $token = 'some_token'; $logger = $this->createMock(LoggerInterface::class); @@ -32,10 +25,7 @@ public function createBotClient_validTokenType_returnsValidClient(): void self::assertSame(sprintf('Bot %s', $token), $tokenPropertyValue); } - /** - * @test - */ - public function createUserClient_validTokenType_returnsValidClient(): void + public function testCreatesUserClient(): void { $token = 'some_token'; $logger = $this->createMock(LoggerInterface::class); diff --git a/tests/unit/Service/Mission/MissionClientTest.php b/tests/unit/Service/Mission/MissionClientTest.php index 6b702a16..d5a5ce76 100644 --- a/tests/unit/Service/Mission/MissionClientTest.php +++ b/tests/unit/Service/Mission/MissionClientTest.php @@ -7,21 +7,16 @@ use App\Service\Mission\Enum\MissionStateEnum; use App\Service\Mission\MissionClient; use App\Service\Mission\MissionStore; -use PHPUnit\Framework\TestCase; +use Codeception\Test\Unit; use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Contracts\HttpClient\ResponseInterface; -/** - * @internal - * @covers \App\Service\Mission\MissionClient - */ -final class MissionClientTest extends TestCase +final class MissionClientTest extends Unit { /** - * @test * @dataProvider provideGetCurrentMissionCases */ - public function getCurrentMission(array $missionData, ?string $expectedTitle, ?string $expectedModlist): void + public function testGetCurrentMission(array $missionData, ?string $expectedTitle, ?string $expectedModlist): void { $mockHttpClient = $this->mockHttpClient($missionData); $mockStore = $this->getMockBuilder(MissionStore::class) diff --git a/tests/unit/Service/SteamApiClient/Helper/SteamHelperTest.php b/tests/unit/Service/SteamApiClient/Helper/SteamHelperTest.php index 29a1a04e..93f854fe 100644 --- a/tests/unit/Service/SteamApiClient/Helper/SteamHelperTest.php +++ b/tests/unit/Service/SteamApiClient/Helper/SteamHelperTest.php @@ -6,56 +6,50 @@ use App\Service\SteamApiClient\Helper\Exception\InvalidWorkshopItemUrlFormatException; use App\Service\SteamApiClient\Helper\SteamHelper; -use PHPUnit\Framework\TestCase; +use Codeception\Attribute\DataProvider; +use Codeception\Test\Unit; -/** - * @internal - * @covers \App\Service\SteamApiClient\Helper\SteamHelper - */ -final class SteamHelperTest extends TestCase +final class SteamHelperTest extends Unit { protected const ITEM_ID = 1934142795; - /** - * @test - * @dataProvider validItemUrls - */ - public function isValidItemUrl_validItemUrl_returnsTrue(string $itemUrl): void + #[DataProvider('validItemUrls')] + public function testValidateValidUrl(string $itemUrl): void { $result = SteamHelper::isValidItemUrl($itemUrl); self::assertTrue($result); } - /** - * @test - * @dataProvider invalidItemUrls - */ - public function isValidItemUrl_invalidItemUrl_returnsFalse(string $itemUrl): void + #[DataProvider('invalidItemUrls')] + public function testValidateInvalidUrl(string $itemUrl): void { $result = SteamHelper::isValidItemUrl($itemUrl); self::assertFalse($result); } - /** - * @test - */ - public function itemIdToItemUrl_validItemId_returnsUrl(): void + public function testConvertItemIdToItemUrl(): void { $itemUrl = SteamHelper::itemIdToItemUrl($this::ITEM_ID); self::assertSame('https://steamcommunity.com/sharedfiles/filedetails/?id=1934142795', $itemUrl); } - /** - * @test - * @dataProvider validItemUrls - */ - public function itemUrlToItemId_validItemUrl_returnsItemId(string $itemUrl): void + #[DataProvider('validItemUrls')] + public function testConvertValidUrlToItemId(string $itemUrl): void { $itemId = SteamHelper::itemUrlToItemId($itemUrl); self::assertSame($this::ITEM_ID, $itemId); } - public function validItemUrls(): iterable + #[DataProvider('invalidItemUrls')] + public function testConvertInvalidUrlToItemId(string $itemUrl): void + { + $this->expectException(InvalidWorkshopItemUrlFormatException::class); + $this->expectExceptionMessage(sprintf('Invalid item URL format for: "%s"', $itemUrl)); + + SteamHelper::itemUrlToItemId($itemUrl); + } + + protected function validItemUrls(): iterable { return [ ['https://steamcommunity.com/sharedfiles/filedetails/?id=1934142795'], @@ -63,22 +57,10 @@ public function validItemUrls(): iterable ]; } - /** - * @test - * @dataProvider invalidItemUrls - */ - public function itemUrlToItemId_invalidItemUrl_throwsException(string $itemUrl): void - { - $this->expectException(InvalidWorkshopItemUrlFormatException::class); - $this->expectExceptionMessage("Invalid item URL format for: \"{$itemUrl}\""); - - SteamHelper::itemUrlToItemId($itemUrl); - } - - public function invalidItemUrls(): iterable + protected function invalidItemUrls(): iterable { return [ - ['invalid url'], + ['url' => 'invalid url'], ]; } } From 27d828ff5272e8f3b72f9f767634a181a5f5673e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Skowro=C5=84ski?= Date: Fri, 13 Oct 2023 01:14:42 +0200 Subject: [PATCH 04/17] Update integration tests --- .../SteamApiClient/SteamApiClientCest.php | 64 ++++++++++++++ .../SteamApiClient/SteamApiClientTest.php | 83 ------------------- ...oviderTest.php => VersionProviderCest.php} | 22 ++--- 3 files changed, 70 insertions(+), 99 deletions(-) create mode 100644 tests/integration/Service/SteamApiClient/SteamApiClientCest.php delete mode 100644 tests/integration/Service/SteamApiClient/SteamApiClientTest.php rename tests/integration/Service/Version/{VersionProviderTest.php => VersionProviderCest.php} (61%) diff --git a/tests/integration/Service/SteamApiClient/SteamApiClientCest.php b/tests/integration/Service/SteamApiClient/SteamApiClientCest.php new file mode 100644 index 00000000..1910703d --- /dev/null +++ b/tests/integration/Service/SteamApiClient/SteamApiClientCest.php @@ -0,0 +1,64 @@ +steamApiClient = $I->grabService(SteamApiClientInterface::class); + } + + public function testGetExistingWorkshopItemInfo(IntegrationTester $I): void + { + $workshopItemInfoDto = $this->steamApiClient->getWorkshopItemInfo($this::ITEM_ID); + + $I->assertSame($this::ITEM_ID, $workshopItemInfoDto->getId()); + $I->assertSame($this::ITEM_NAME, $workshopItemInfoDto->getName()); + $I->assertSame($this::ITEM_GAME_ID, $workshopItemInfoDto->getGameId()); + } + + public function testGetNonExistingWorkshopItemInfo(IntegrationTester $I): void + { + $I->expectThrowable( + new WorkshopItemNotFoundException(sprintf('No items found by item id "%s"!', 1)), + fn () => $this->steamApiClient->getWorkshopItemInfo(1) + ); + } + + public function testGetExistingAppInfo(IntegrationTester $I): void + { + $appInfoDto = $this->steamApiClient->getAppInfo($this::APP_ID); + + $I->assertSame($this::APP_ID, $appInfoDto->getId()); + $I->assertSame($this::APP_NAME, $appInfoDto->getName()); + $I->assertSame($this::APP_TYPE, $appInfoDto->getType()); + $I->assertSame($this::APP_GAME_ID, $appInfoDto->getGameId()); + } + + public function testGetNonExistingAppInfo(IntegrationTester $I): void + { + $I->expectThrowable( + new AppNotFoundException(sprintf('No apps found by app id "%s"!', 1)), + fn () => $this->steamApiClient->getAppInfo(1) + ); + } +} diff --git a/tests/integration/Service/SteamApiClient/SteamApiClientTest.php b/tests/integration/Service/SteamApiClient/SteamApiClientTest.php deleted file mode 100644 index f60ba213..00000000 --- a/tests/integration/Service/SteamApiClient/SteamApiClientTest.php +++ /dev/null @@ -1,83 +0,0 @@ -steamApiClient = self::getContainer()->get(SteamApiClientInterface::class); - } - - /** - * @test - */ - public function getWorkshopItemInfo_existingItem_returnsItemDto(): void - { - $workshopItemInfoDto = $this->steamApiClient->getWorkshopItemInfo($this::ITEM_ID); - - self::assertSame($this::ITEM_ID, $workshopItemInfoDto->getId()); - self::assertSame($this::ITEM_NAME, $workshopItemInfoDto->getName()); - self::assertSame($this::ITEM_GAME_ID, $workshopItemInfoDto->getGameId()); - } - - /** - * @test - */ - public function getWorkshopItemInfo_nonExistingItem_throwsException(): void - { - $this->expectException(WorkshopItemNotFoundException::class); - $this->expectExceptionMessage(sprintf('No items found by item id "%s"!', 1)); - - $this->steamApiClient->getWorkshopItemInfo(1); - } - - /** - * @test - */ - public function getAppInfo_existingApp_returnsAppInfoDto(): void - { - $appInfoDto = $this->steamApiClient->getAppInfo($this::APP_ID); - - self::assertSame($this::APP_ID, $appInfoDto->getId()); - self::assertSame($this::APP_NAME, $appInfoDto->getName()); - self::assertSame($this::APP_TYPE, $appInfoDto->getType()); - self::assertSame($this::APP_GAME_ID, $appInfoDto->getGameId()); - } - - /** - * @test - */ - public function getAppInfo_nonExistingApp_throwsException(): void - { - $this->expectException(AppNotFoundException::class); - $this->expectExceptionMessage(sprintf('No apps found by app id "%s"!', 1)); - - $this->steamApiClient->getAppInfo(1); - } -} diff --git a/tests/integration/Service/Version/VersionProviderTest.php b/tests/integration/Service/Version/VersionProviderCest.php similarity index 61% rename from tests/integration/Service/Version/VersionProviderTest.php rename to tests/integration/Service/Version/VersionProviderCest.php index 49dc91b9..b68511e3 100644 --- a/tests/integration/Service/Version/VersionProviderTest.php +++ b/tests/integration/Service/Version/VersionProviderCest.php @@ -5,18 +5,11 @@ namespace App\Tests\Integration\Service\Version; use App\Service\Version\VersionProvider; -use PHPUnit\Framework\TestCase; +use App\Tests\IntegrationTester; -/** - * @internal - * @covers \App\Service\Version\VersionProvider - */ -final class VersionProviderTest extends TestCase +final class VersionProviderCest { - /** - * @test - */ - public function getVersion_versionFileExist_returnsVersion(): void + public function testGetVersionNumberWhenFileExist(IntegrationTester $I): void { $fileContent = '1.0.0'; $fileName = 'VERSION'; @@ -27,15 +20,12 @@ public function getVersion_versionFileExist_returnsVersion(): void $versionProvider = new VersionProvider($fileDir); $version = $versionProvider->getVersion(); - self::assertSame($fileContent, $version); + $I->assertSame($fileContent, $version); unlink($filePath); } - /** - * @test - */ - public function getVersion_versionFileNotExist_returnsDefaultVersion(): void + public function testGetDefaultVersionNumberWhenFileNotExist(IntegrationTester $I): void { $defaultVersion = 'dev'; $fileName = 'some_non_existing_file'; @@ -44,6 +34,6 @@ public function getVersion_versionFileNotExist_returnsDefaultVersion(): void $versionProvider = new VersionProvider($fileDir, $fileName, $defaultVersion); $version = $versionProvider->getVersion(); - self::assertSame($defaultVersion, $version); + $I->assertSame($defaultVersion, $version); } } From 869b5d20db0ab3d96e47eae890400eefb9ba2855 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Skowro=C5=84ski?= Date: Sat, 28 Oct 2023 17:43:52 +0200 Subject: [PATCH 05/17] Remove existing functional tests --- src/Test/Enum/RouteEnum.php | 52 ------- src/Test/Traits/AssertsTrait.php | 51 ------- src/Test/Traits/DataProvidersTrait.php | 52 ------- .../Attendance/CreateAttendanceActionTest.php | 90 ------------ .../ModList/GetModListByNameActionTest.php | 130 ----------------- .../ModList/GetModListsActionTest.php | 59 -------- .../ModList/GetModListsByIdActionTest.php | 131 ------------------ .../Controller/Home/IndexActionTest.php | 61 -------- .../Controller/Home/JoinUsActionTest.php | 61 -------- .../Controller/Home/MissionsActionTest.php | 61 -------- .../Controller/Mod/CreateActionTest.php | 68 --------- .../Controller/Mod/DeleteActionTest.php | 100 ------------- .../Controller/Mod/ListActionTest.php | 68 --------- .../Controller/ModGroup/CreateActionTest.php | 68 --------- .../Controller/ModGroup/DeleteActionTest.php | 98 ------------- .../Controller/ModGroup/ListActionTest.php | 68 --------- .../Controller/ModList/CreateActionTest.php | 68 --------- .../Controller/ModList/DeleteActionTest.php | 98 ------------- .../Controller/ModList/ListActionTest.php | 68 --------- .../ModListPublic/CustomizeActionTest.php | 66 --------- .../ModListPublic/DownloadActionTest.php | 130 ----------------- .../ModListPublic/SelectActionTest.php | 47 ------- .../Controller/User/DeleteActionTest.php | 108 --------------- .../Controller/User/ListActionTest.php | 68 --------- .../Controller/User/UpdateActionTest.php | 91 ------------ .../Controller/UserGroup/CreateActionTest.php | 68 --------- .../Controller/UserGroup/DeleteActionTest.php | 98 ------------- .../Controller/UserGroup/ListActionTest.php | 68 --------- 28 files changed, 2196 deletions(-) delete mode 100644 src/Test/Enum/RouteEnum.php delete mode 100644 src/Test/Traits/AssertsTrait.php delete mode 100644 src/Test/Traits/DataProvidersTrait.php delete mode 100644 tests/functional/Api/Controller/Attendance/CreateAttendanceActionTest.php delete mode 100644 tests/functional/Api/Controller/ModList/GetModListByNameActionTest.php delete mode 100644 tests/functional/Api/Controller/ModList/GetModListsActionTest.php delete mode 100644 tests/functional/Api/Controller/ModList/GetModListsByIdActionTest.php delete mode 100644 tests/functional/Controller/Home/IndexActionTest.php delete mode 100644 tests/functional/Controller/Home/JoinUsActionTest.php delete mode 100644 tests/functional/Controller/Home/MissionsActionTest.php delete mode 100644 tests/functional/Controller/Mod/CreateActionTest.php delete mode 100644 tests/functional/Controller/Mod/DeleteActionTest.php delete mode 100644 tests/functional/Controller/Mod/ListActionTest.php delete mode 100644 tests/functional/Controller/ModGroup/CreateActionTest.php delete mode 100644 tests/functional/Controller/ModGroup/DeleteActionTest.php delete mode 100644 tests/functional/Controller/ModGroup/ListActionTest.php delete mode 100644 tests/functional/Controller/ModList/CreateActionTest.php delete mode 100644 tests/functional/Controller/ModList/DeleteActionTest.php delete mode 100644 tests/functional/Controller/ModList/ListActionTest.php delete mode 100644 tests/functional/Controller/ModListPublic/CustomizeActionTest.php delete mode 100644 tests/functional/Controller/ModListPublic/DownloadActionTest.php delete mode 100644 tests/functional/Controller/ModListPublic/SelectActionTest.php delete mode 100644 tests/functional/Controller/User/DeleteActionTest.php delete mode 100644 tests/functional/Controller/User/ListActionTest.php delete mode 100644 tests/functional/Controller/User/UpdateActionTest.php delete mode 100644 tests/functional/Controller/UserGroup/CreateActionTest.php delete mode 100644 tests/functional/Controller/UserGroup/DeleteActionTest.php delete mode 100644 tests/functional/Controller/UserGroup/ListActionTest.php diff --git a/src/Test/Enum/RouteEnum.php b/src/Test/Enum/RouteEnum.php deleted file mode 100644 index 61d9b34a..00000000 --- a/src/Test/Enum/RouteEnum.php +++ /dev/null @@ -1,52 +0,0 @@ -filter('.icon-teamspeak a')->attr('href'); - self::assertSame($expectedUrl, $url); - } - - public static function assertResponseContainsModListAttachmentHeader(Response $response, ModList $modList): void - { - $contentDispositionHeader = $response->headers->get('Content-Disposition'); - $pattern = "/^attachment; filename=\"ArmaForces {$modList->getName()} \\d{4}_\\d{2}_\\d{2} \\d{2}_\\d{2}.html\"$/"; - - self::assertMatchesRegularExpression($pattern, $contentDispositionHeader); - } - - public static function assertLauncherPresetContainsMods(Crawler $crawler, array $expectedMods): void - { - $expectedMods = array_map(static function (SteamWorkshopMod $steamWorkshopMod) { - return [ - 'name' => $steamWorkshopMod->getName(), - 'url' => "https://steamcommunity.com/sharedfiles/filedetails/?id={$steamWorkshopMod->getItemId()}", - ]; - }, $expectedMods); - - $modContainerNodes = $crawler->filter('[data-type="ModContainer"]'); - $presetMods = array_map(static function (\DOMNode $modContainerNode) { - $modContainerCrawler = (new Crawler($modContainerNode)); - - return [ - 'name' => $modContainerCrawler->filter('[data-type="DisplayName"]')->html(), - 'url' => $modContainerCrawler->filter('[data-type="Link"]')->attr('href'), - ]; - }, iterator_to_array($modContainerNodes->getIterator())); - - self::assertSame(var_export($expectedMods, true), var_export($presetMods, true)); - } -} diff --git a/src/Test/Traits/DataProvidersTrait.php b/src/Test/Traits/DataProvidersTrait.php deleted file mode 100644 index ac9823c0..00000000 --- a/src/Test/Traits/DataProvidersTrait.php +++ /dev/null @@ -1,52 +0,0 @@ - [''], - 'Regular user' => [RegularUserFixture::ID], - 'Admin user' => [AdminUserFixture::ID], - ]; - } - - public function registeredUsersDataProvider(): array - { - return [ - 'Regular user' => [RegularUserFixture::ID], - 'Admin user' => [AdminUserFixture::ID], - ]; - } - - public function modsDataProvider(): array - { - return [ - 'Steam Workshop, required' => [ArmaForcesModsModFixture::ID], - ]; - } - - public function modGroupsDataProvider(): array - { - return [ - [RhsModGroupFixture::ID], - ]; - } - - public function modListsDataProvider(): array - { - return [ - [DefaultModListFixture::ID], - ]; - } -} diff --git a/tests/functional/Api/Controller/Attendance/CreateAttendanceActionTest.php b/tests/functional/Api/Controller/Attendance/CreateAttendanceActionTest.php deleted file mode 100644 index 09847726..00000000 --- a/tests/functional/Api/Controller/Attendance/CreateAttendanceActionTest.php +++ /dev/null @@ -1,90 +0,0 @@ -client = self::createClient([], ['headers' => ['Accept' => 'application/json']]); - } - - /** - * @test - */ - public function createAttendanceAction_validApiKey_returnsSuccessfulResponse(): void - { - $this->client->request(Request::METHOD_POST, RouteEnum::API_ATTENDANCE_CREATE, [ - 'headers' => [ - 'X-API-KEY' => 'test_key', - ], - 'json' => [ - 'missionId' => 'mission_99', - 'playerId' => 76561198048200529, - ], - ]); - - $this::assertResponseStatusCodeSame(Response::HTTP_CREATED); - } - - /** - * @test - */ - public function createAttendanceAction_invalidApiKey_returnsForbiddenResponse(): void - { - $this->client->request(Request::METHOD_POST, RouteEnum::API_ATTENDANCE_CREATE, [ - 'headers' => [ - 'X-API-KEY' => '', - ], - 'json' => [ - 'missionId' => 'mission_99', - 'playerId' => 76561198048200529, - ], - ]); - - $this::assertResponseStatusCodeSame(Response::HTTP_FORBIDDEN); - $this::assertJsonContains([ - 'detail' => 'Invalid or missing API key provided!', - ]); - } - - /** - * @test - */ - public function createAttendanceAction_duplicatedEntry_returnsUnprocessableEntityResponse(): void - { - $this->client->request(Request::METHOD_POST, RouteEnum::API_ATTENDANCE_CREATE, [ - 'headers' => [ - 'X-API-KEY' => 'test_key', - ], - 'json' => [ - 'missionId' => 'mission_1', - 'playerId' => 76561198048200529, - ], - ]); - - $this::assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY); - $this::assertJsonContains([ - 'detail' => 'Attendance of player "76561198048200529" in mission "mission_1" already exists.', - ]); - } -} diff --git a/tests/functional/Api/Controller/ModList/GetModListByNameActionTest.php b/tests/functional/Api/Controller/ModList/GetModListByNameActionTest.php deleted file mode 100644 index d54d9a6c..00000000 --- a/tests/functional/Api/Controller/ModList/GetModListByNameActionTest.php +++ /dev/null @@ -1,130 +0,0 @@ -client = self::createClient([], ['headers' => ['Accept' => 'application/json']]); - $this->userRepository = self::getContainer()->get(UserRepository::class); - $this->modListRepository = self::getContainer()->get(ModListRepository::class); - } - - /** - * @test - * @dataProvider allUserTypesDataProvider - */ - public function getModListByNameAction_authorizedUser_returnsSuccessfulResponse(string $userId): void - { - $user = $this->userRepository->find($userId); - $modList = $this->modListRepository->find(DefaultModListFixture::ID); - - !$user ?: $this->client->getKernelBrowser()->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::API_MOD_LIST_GET_BY_NAME, $modList->getName())); - - $this::assertResponseStatusCodeSame(Response::HTTP_OK); - $this::assertJsonContains([ - 'id' => 'f3e04dae-18a8-4533-99ea-d6d763ebabcf', - 'name' => 'Default', - 'active' => true, - 'approved' => false, - 'createdAt' => '2020-01-01T00:00:00+00:00', - 'lastUpdatedAt' => null, - 'mods' => [ - [ - 'id' => '37f58e30-5194-4594-89af-4a82c7fc02be', - 'name' => 'ACE Interaction Menu Expansion', - 'createdAt' => '2020-01-01T00:00:00+00:00', - 'lastUpdatedAt' => null, - 'source' => 'steam_workshop', - 'status' => null, - 'type' => 'optional', - 'itemId' => 1376867375, - 'directory' => null, - ], - [ - 'id' => '2f1d2dea-a7a6-4509-b478-66a980d724ca', - 'name' => 'ArmaForces - ACE Medical [OBSOLETE]', - 'createdAt' => '2020-01-01T00:00:00+00:00', - 'lastUpdatedAt' => null, - 'source' => 'steam_workshop', - 'status' => 'broken', - 'type' => 'required', - 'itemId' => 1704054308, - 'directory' => null, - ], - [ - 'id' => '0e4e059c-eef6-42a9-aec3-abdab344ec21', - 'name' => 'ArmaForces - Mods', - 'createdAt' => '2020-01-01T00:00:00+00:00', - 'lastUpdatedAt' => null, - 'source' => 'steam_workshop', - 'status' => null, - 'type' => 'required', - 'itemId' => 1934142795, - 'directory' => null, - ], - [ - 'id' => 'b8e88103-69d2-438b-8d89-933ccfdb3a5a', - 'name' => '[OBSOLETE] ArmaForces - JBAD Building Fix', - 'source' => 'steam_workshop', - 'status' => 'disabled', - 'type' => 'required', - 'itemId' => 1781106281, - 'directory' => null, - ], - [ - 'id' => '7e11c37e-930e-49e8-a87d-8f942d98edb0', - 'name' => '[legacy] ArmaForces - Mods', - 'source' => 'steam_workshop', - 'status' => 'deprecated', - 'type' => 'required', - 'itemId' => 1639399387, - 'directory' => null, - ], - ], - ]); - } - - /** - * @test - * @dataProvider allUserTypesDataProvider - */ - public function getModListByNameAction_nonExistingModList_returnsNotFoundResponse(string $userId): void - { - $user = $this->userRepository->find($userId); - - !$user ?: $this->client->getKernelBrowser()->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::API_MOD_LIST_GET_BY_NAME, 'some_name')); - - $this::assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND); - $this::assertJsonContains([ - 'detail' => 'Not Found', - ]); - } -} diff --git a/tests/functional/Api/Controller/ModList/GetModListsActionTest.php b/tests/functional/Api/Controller/ModList/GetModListsActionTest.php deleted file mode 100644 index cbe6949b..00000000 --- a/tests/functional/Api/Controller/ModList/GetModListsActionTest.php +++ /dev/null @@ -1,59 +0,0 @@ -client = self::createClient([], ['headers' => ['Accept' => 'application/json']]); - $this->userRepository = self::getContainer()->get(UserRepository::class); - } - - /** - * @test - * @dataProvider allUserTypesDataProvider - */ - public function getModListsAction_authorizedUser_returnsSuccessfulResponse(string $userId): void - { - $user = $this->userRepository->find($userId); - - !$user ?: $this->client->getKernelBrowser()->loginUser($user); - $this->client->request(Request::METHOD_GET, RouteEnum::API_MOD_LIST_LIST); - - $this::assertResponseStatusCodeSame(Response::HTTP_OK); - $this::assertJsonContains([ - 'data' => [ - [ - 'id' => 'f3e04dae-18a8-4533-99ea-d6d763ebabcf', - 'name' => 'Default', - 'active' => true, - 'approved' => false, - 'createdAt' => '2020-01-01T00:00:00+00:00', - 'lastUpdatedAt' => null, - ], - ], - ]); - } -} diff --git a/tests/functional/Api/Controller/ModList/GetModListsByIdActionTest.php b/tests/functional/Api/Controller/ModList/GetModListsByIdActionTest.php deleted file mode 100644 index 6ad4faca..00000000 --- a/tests/functional/Api/Controller/ModList/GetModListsByIdActionTest.php +++ /dev/null @@ -1,131 +0,0 @@ -client = self::createClient([], ['headers' => ['Accept' => 'application/json']]); - $this->userRepository = self::getContainer()->get(UserRepository::class); - $this->modListRepository = self::getContainer()->get(ModListRepository::class); - } - - /** - * @test - * @dataProvider allUserTypesDataProvider - */ - public function getModListByIdAction_authorizedUser_returnsSuccessfulResponse(string $userId): void - { - $user = $this->userRepository->find($userId); - $mod = $this->modListRepository->find(DefaultModListFixture::ID); - - !$user ?: $this->client->getKernelBrowser()->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::API_MOD_LIST_GET_BY_ID, $mod->getId())); - - $this::assertResponseStatusCodeSame(Response::HTTP_OK); - $this::assertJsonContains([ - 'id' => 'f3e04dae-18a8-4533-99ea-d6d763ebabcf', - 'name' => 'Default', - 'active' => true, - 'approved' => false, - 'createdAt' => '2020-01-01T00:00:00+00:00', - 'lastUpdatedAt' => null, - 'mods' => [ - [ - 'id' => '37f58e30-5194-4594-89af-4a82c7fc02be', - 'name' => 'ACE Interaction Menu Expansion', - 'createdAt' => '2020-01-01T00:00:00+00:00', - 'lastUpdatedAt' => null, - 'source' => 'steam_workshop', - 'status' => null, - 'type' => 'optional', - 'itemId' => 1376867375, - 'directory' => null, - ], - [ - 'id' => '2f1d2dea-a7a6-4509-b478-66a980d724ca', - 'name' => 'ArmaForces - ACE Medical [OBSOLETE]', - 'createdAt' => '2020-01-01T00:00:00+00:00', - 'lastUpdatedAt' => null, - 'source' => 'steam_workshop', - 'status' => 'broken', - 'type' => 'required', - 'itemId' => 1704054308, - 'directory' => null, - ], - [ - 'id' => '0e4e059c-eef6-42a9-aec3-abdab344ec21', - 'name' => 'ArmaForces - Mods', - 'createdAt' => '2020-01-01T00:00:00+00:00', - 'lastUpdatedAt' => null, - 'source' => 'steam_workshop', - 'status' => null, - 'type' => 'required', - 'itemId' => 1934142795, - 'directory' => null, - ], - [ - 'id' => 'b8e88103-69d2-438b-8d89-933ccfdb3a5a', - 'name' => '[OBSOLETE] ArmaForces - JBAD Building Fix', - 'source' => 'steam_workshop', - 'status' => 'disabled', - 'type' => 'required', - 'itemId' => 1781106281, - 'directory' => null, - ], - [ - 'id' => '7e11c37e-930e-49e8-a87d-8f942d98edb0', - 'name' => '[legacy] ArmaForces - Mods', - 'source' => 'steam_workshop', - 'status' => 'deprecated', - 'type' => 'required', - 'itemId' => 1639399387, - 'directory' => null, - ], - ], - ]); - } - - /** - * @test - * @dataProvider allUserTypesDataProvider - */ - public function getModListByIdAction_nonExistingModList_returnsNotFoundResponse(string $userId): void - { - $user = $this->userRepository->find($userId); - - !$user ?: $this->client->getKernelBrowser()->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::API_MOD_LIST_GET_BY_ID, Uuid::uuid4()->toString())); - - $this::assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND); - $this::assertJsonContains([ - 'detail' => 'Not Found', - ]); - } -} diff --git a/tests/functional/Controller/Home/IndexActionTest.php b/tests/functional/Controller/Home/IndexActionTest.php deleted file mode 100644 index 69dc675c..00000000 --- a/tests/functional/Controller/Home/IndexActionTest.php +++ /dev/null @@ -1,61 +0,0 @@ -client = self::createClient(); - $this->userRepository = self::getContainer()->get(UserRepository::class); - } - - /** - * @test - */ - public function indexAction_anonymousUser_returnsSuccessfulResponse(): void - { - $crawler = $this->client->request(Request::METHOD_GET, RouteEnum::HOME_INDEX); - - $this::assertResponseStatusCodeSame(Response::HTTP_OK); - $this::assertTeamSpeakUrlVisible($crawler, false); - } - - /** - * @test - * @dataProvider registeredUsersDataProvider - */ - public function indexAction_authenticatedUser_returnsSuccessfulResponse(string $userId): void - { - $user = $this->userRepository->find($userId); - - $this->client->loginUser($user); - $crawler = $this->client->request(Request::METHOD_GET, RouteEnum::HOME_INDEX); - - $this::assertResponseStatusCodeSame(Response::HTTP_OK); - $this::assertTeamSpeakUrlVisible($crawler, true); - } -} diff --git a/tests/functional/Controller/Home/JoinUsActionTest.php b/tests/functional/Controller/Home/JoinUsActionTest.php deleted file mode 100644 index f272a53b..00000000 --- a/tests/functional/Controller/Home/JoinUsActionTest.php +++ /dev/null @@ -1,61 +0,0 @@ -client = self::createClient(); - $this->userRepository = self::getContainer()->get(UserRepository::class); - } - - /** - * @test - */ - public function joinUsAction_anonymousUser_returnsSuccessfulResponse(): void - { - $crawler = $this->client->request(Request::METHOD_GET, RouteEnum::HOME_JOIN_US); - - $this::assertResponseStatusCodeSame(Response::HTTP_OK); - $this::assertTeamSpeakUrlVisible($crawler, false); - } - - /** - * @test - * @dataProvider registeredUsersDataProvider - */ - public function joinUsAction_authenticatedUser_returnsSuccessfulResponse(string $userId): void - { - $user = $this->userRepository->find($userId); - - $this->client->loginUser($user); - $crawler = $this->client->request(Request::METHOD_GET, RouteEnum::HOME_JOIN_US); - - $this::assertResponseStatusCodeSame(Response::HTTP_OK); - $this::assertTeamSpeakUrlVisible($crawler, true); - } -} diff --git a/tests/functional/Controller/Home/MissionsActionTest.php b/tests/functional/Controller/Home/MissionsActionTest.php deleted file mode 100644 index 882bca4d..00000000 --- a/tests/functional/Controller/Home/MissionsActionTest.php +++ /dev/null @@ -1,61 +0,0 @@ -client = self::createClient(); - $this->userRepository = self::getContainer()->get(UserRepository::class); - } - - /** - * @test - */ - public function missionsAction_anonymousUser_returnsSuccessfulResponse(): void - { - $crawler = $this->client->request(Request::METHOD_GET, RouteEnum::HOME_MISSIONS); - - $this::assertResponseStatusCodeSame(Response::HTTP_OK); - $this::assertTeamSpeakUrlVisible($crawler, false); - } - - /** - * @test - * @dataProvider registeredUsersDataProvider - */ - public function missionsAction_authenticatedUser_returnsSuccessfulResponse(string $userId): void - { - $user = $this->userRepository->find($userId); - - $this->client->loginUser($user); - $crawler = $this->client->request(Request::METHOD_GET, RouteEnum::HOME_MISSIONS); - - $this::assertResponseStatusCodeSame(Response::HTTP_OK); - $this::assertTeamSpeakUrlVisible($crawler, true); - } -} diff --git a/tests/functional/Controller/Mod/CreateActionTest.php b/tests/functional/Controller/Mod/CreateActionTest.php deleted file mode 100644 index ffa19d0a..00000000 --- a/tests/functional/Controller/Mod/CreateActionTest.php +++ /dev/null @@ -1,68 +0,0 @@ -client = self::createClient(); - $this->userRepository = self::getContainer()->get(UserRepository::class); - } - - /** - * @test - */ - public function createAction_anonymousUser_returnsRedirectResponse(): void - { - $this->client->request(Request::METHOD_GET, RouteEnum::MOD_CREATE); - - $this::assertResponseRedirects(RouteEnum::SECURITY_CONNECT_DISCORD, Response::HTTP_FOUND); - } - - /** - * @test - */ - public function createAction_unauthorizedUser_returnsForbiddenResponse(): void - { - $user = $this->userRepository->find(RegularUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, RouteEnum::MOD_CREATE); - - $this::assertResponseStatusCodeSame(Response::HTTP_FORBIDDEN); - } - - /** - * @test - */ - public function createAction_authorizedUser_returnsSuccessfulResponse(): void - { - $user = $this->userRepository->find(AdminUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, RouteEnum::MOD_CREATE); - - $this::assertResponseStatusCodeSame(Response::HTTP_OK); - } -} diff --git a/tests/functional/Controller/Mod/DeleteActionTest.php b/tests/functional/Controller/Mod/DeleteActionTest.php deleted file mode 100644 index b7695822..00000000 --- a/tests/functional/Controller/Mod/DeleteActionTest.php +++ /dev/null @@ -1,100 +0,0 @@ -client = self::createClient(); - $this->userRepository = self::getContainer()->get(UserRepository::class); - $this->modRepository = self::getContainer()->get(ModRepository::class); - } - - /** - * @test - * @dataProvider modsDataProvider - */ - public function deleteAction_anonymousUser_returnsRedirectResponse(string $modId): void - { - /** @var AbstractMod $subjectMod */ - $subjectMod = $this->modRepository->find($modId); - - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_DELETE, $subjectMod->getId())); - - $this::assertResponseRedirects(RouteEnum::SECURITY_CONNECT_DISCORD, Response::HTTP_FOUND); - } - - /** - * @test - * @dataProvider modsDataProvider - */ - public function deleteAction_unauthorizedUser_returnsForbiddenResponse(string $modId): void - { - $user = $this->userRepository->find(RegularUserFixture::ID); - $subjectMod = $this->modRepository->find($modId); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_DELETE, $subjectMod->getId())); - - $this::assertResponseStatusCodeSame(Response::HTTP_FORBIDDEN); - } - - /** - * @test - * @dataProvider modsDataProvider - */ - public function deleteAction_authorizedUser_returnsSuccessfulResponse(string $modId): void - { - $user = $this->userRepository->find(AdminUserFixture::ID); - $subjectMod = $this->modRepository->find($modId); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_DELETE, $subjectMod->getId())); - - $this::assertResponseRedirects(RouteEnum::MOD_LIST, Response::HTTP_FOUND); - - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_DELETE, $subjectMod->getId())); - - $this::assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND); - } - - /** - * @test - */ - public function deleteAction_authorizedUser_returnsNotFoundResponse(): void - { - $user = $this->userRepository->find(AdminUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_DELETE, 'non-existing-id')); - - $this::assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND); - } -} diff --git a/tests/functional/Controller/Mod/ListActionTest.php b/tests/functional/Controller/Mod/ListActionTest.php deleted file mode 100644 index 870fb68f..00000000 --- a/tests/functional/Controller/Mod/ListActionTest.php +++ /dev/null @@ -1,68 +0,0 @@ -client = self::createClient(); - $this->userRepository = self::getContainer()->get(UserRepository::class); - } - - /** - * @test - */ - public function listAction_anonymousUser_returnsRedirectResponse(): void - { - $this->client->request(Request::METHOD_GET, RouteEnum::MOD_LIST); - - $this::assertResponseRedirects(RouteEnum::SECURITY_CONNECT_DISCORD, Response::HTTP_FOUND); - } - - /** - * @test - */ - public function listAction_unauthorizedUser_returnsForbiddenResponse(): void - { - $user = $this->userRepository->find(RegularUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, RouteEnum::MOD_LIST); - - $this::assertResponseStatusCodeSame(Response::HTTP_FORBIDDEN); - } - - /** - * @test - */ - public function listAction_authorizedUser_returnsSuccessfulResponse(): void - { - $user = $this->userRepository->find(AdminUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, RouteEnum::MOD_LIST); - - $this::assertResponseStatusCodeSame(Response::HTTP_OK); - } -} diff --git a/tests/functional/Controller/ModGroup/CreateActionTest.php b/tests/functional/Controller/ModGroup/CreateActionTest.php deleted file mode 100644 index 200a57e2..00000000 --- a/tests/functional/Controller/ModGroup/CreateActionTest.php +++ /dev/null @@ -1,68 +0,0 @@ -client = self::createClient(); - $this->userRepository = self::getContainer()->get(UserRepository::class); - } - - /** - * @test - */ - public function createAction_anonymousUser_returnsRedirectResponse(): void - { - $this->client->request(Request::METHOD_GET, RouteEnum::MOD_GROUP_CREATE); - - $this::assertResponseRedirects(RouteEnum::SECURITY_CONNECT_DISCORD, Response::HTTP_FOUND); - } - - /** - * @test - */ - public function createAction_unauthorizedUser_returnsForbiddenResponse(): void - { - $user = $this->userRepository->find(RegularUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, RouteEnum::MOD_GROUP_CREATE); - - $this::assertResponseStatusCodeSame(Response::HTTP_FORBIDDEN); - } - - /** - * @test - */ - public function createAction_authorizedUser_returnsSuccessfulResponse(): void - { - $user = $this->userRepository->find(AdminUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, RouteEnum::MOD_GROUP_CREATE); - - $this::assertResponseStatusCodeSame(Response::HTTP_OK); - } -} diff --git a/tests/functional/Controller/ModGroup/DeleteActionTest.php b/tests/functional/Controller/ModGroup/DeleteActionTest.php deleted file mode 100644 index 55ae28ea..00000000 --- a/tests/functional/Controller/ModGroup/DeleteActionTest.php +++ /dev/null @@ -1,98 +0,0 @@ -client = self::createClient(); - $this->userRepository = self::getContainer()->get(UserRepository::class); - $this->modGroupRepository = self::getContainer()->get(ModGroupRepository::class); - } - - /** - * @test - * @dataProvider modGroupsDataProvider - */ - public function deleteAction_anonymousUser_returnsRedirectResponse(string $modGroupId): void - { - $subjectModGroup = $this->modGroupRepository->find($modGroupId); - - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_GROUP_DELETE, $subjectModGroup->getName())); - - $this::assertResponseRedirects(RouteEnum::SECURITY_CONNECT_DISCORD, Response::HTTP_FOUND); - } - - /** - * @test - * @dataProvider modGroupsDataProvider - */ - public function deleteAction_unauthorizedUser_returnsForbiddenResponse(string $modGroupId): void - { - $user = $this->userRepository->find(RegularUserFixture::ID); - $subjectModGroup = $this->modGroupRepository->find($modGroupId); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_GROUP_DELETE, $subjectModGroup->getName())); - - $this::assertResponseStatusCodeSame(Response::HTTP_FORBIDDEN); - } - - /** - * @test - * @dataProvider modGroupsDataProvider - */ - public function deleteAction_authorizedUser_returnsSuccessfulResponse(string $modGroupId): void - { - $user = $this->userRepository->find(AdminUserFixture::ID); - $subjectModGroup = $this->modGroupRepository->find($modGroupId); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_GROUP_DELETE, $subjectModGroup->getName())); - - $this::assertResponseRedirects(RouteEnum::MOD_GROUP_LIST); - - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_GROUP_DELETE, $subjectModGroup->getName())); - - $this::assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND); - } - - /** - * @test - */ - public function deleteAction_authorizedUser_returnsNotFoundResponse(): void - { - $user = $this->userRepository->find(AdminUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_GROUP_DELETE, 'non-existing-name')); - - $this::assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND); - } -} diff --git a/tests/functional/Controller/ModGroup/ListActionTest.php b/tests/functional/Controller/ModGroup/ListActionTest.php deleted file mode 100644 index d4f4c5fb..00000000 --- a/tests/functional/Controller/ModGroup/ListActionTest.php +++ /dev/null @@ -1,68 +0,0 @@ -client = self::createClient(); - $this->userRepository = self::getContainer()->get(UserRepository::class); - } - - /** - * @test - */ - public function listAction_anonymousUser_returnsRedirectResponse(): void - { - $this->client->request(Request::METHOD_GET, RouteEnum::MOD_GROUP_LIST); - - $this::assertResponseRedirects(RouteEnum::SECURITY_CONNECT_DISCORD, Response::HTTP_FOUND); - } - - /** - * @test - */ - public function listAction_unauthorizedUser_returnsForbiddenResponse(): void - { - $user = $this->userRepository->find(RegularUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, RouteEnum::MOD_GROUP_LIST); - - $this::assertResponseStatusCodeSame(Response::HTTP_FORBIDDEN); - } - - /** - * @test - */ - public function listAction_authorizedUser_returnsSuccessfulResponse(): void - { - $user = $this->userRepository->find(AdminUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, RouteEnum::MOD_GROUP_LIST); - - $this::assertResponseStatusCodeSame(Response::HTTP_OK); - } -} diff --git a/tests/functional/Controller/ModList/CreateActionTest.php b/tests/functional/Controller/ModList/CreateActionTest.php deleted file mode 100644 index 3d19bac8..00000000 --- a/tests/functional/Controller/ModList/CreateActionTest.php +++ /dev/null @@ -1,68 +0,0 @@ -client = self::createClient(); - $this->userRepository = self::getContainer()->get(UserRepository::class); - } - - /** - * @test - */ - public function createAction_anonymousUser_returnsRedirectResponse(): void - { - $this->client->request(Request::METHOD_GET, RouteEnum::MOD_LIST_CREATE); - - $this::assertResponseRedirects(RouteEnum::SECURITY_CONNECT_DISCORD, Response::HTTP_FOUND); - } - - /** - * @test - */ - public function createAction_unauthorizedUser_returnsForbiddenResponse(): void - { - $user = $this->userRepository->find(RegularUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, RouteEnum::MOD_LIST_CREATE); - - $this::assertResponseStatusCodeSame(Response::HTTP_FORBIDDEN); - } - - /** - * @test - */ - public function createAction_authorizedUser_returnsSuccessfulResponse(): void - { - $user = $this->userRepository->find(AdminUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, RouteEnum::MOD_LIST_CREATE); - - $this::assertResponseStatusCodeSame(Response::HTTP_OK); - } -} diff --git a/tests/functional/Controller/ModList/DeleteActionTest.php b/tests/functional/Controller/ModList/DeleteActionTest.php deleted file mode 100644 index 19b344d9..00000000 --- a/tests/functional/Controller/ModList/DeleteActionTest.php +++ /dev/null @@ -1,98 +0,0 @@ -client = self::createClient(); - $this->userRepository = self::getContainer()->get(UserRepository::class); - $this->modListRepository = self::getContainer()->get(ModListRepository::class); - } - - /** - * @test - * @dataProvider modListsDataProvider - */ - public function deleteAction_anonymousUser_returnsRedirectResponse(string $modListId): void - { - $subjectModList = $this->modListRepository->find($modListId); - - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_LIST_DELETE, $subjectModList->getName())); - - $this::assertResponseRedirects(RouteEnum::SECURITY_CONNECT_DISCORD, Response::HTTP_FOUND); - } - - /** - * @test - * @dataProvider modListsDataProvider - */ - public function deleteAction_unauthorizedUser_returnsForbiddenResponse(string $modListId): void - { - $user = $this->userRepository->find(RegularUserFixture::ID); - $subjectModList = $this->modListRepository->find($modListId); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_LIST_DELETE, $subjectModList->getName())); - - $this::assertResponseStatusCodeSame(Response::HTTP_FORBIDDEN); - } - - /** - * @test - * @dataProvider modListsDataProvider - */ - public function deleteAction_authorizedUser_returnsSuccessfulResponse(string $modListId): void - { - $user = $this->userRepository->find(AdminUserFixture::ID); - $subjectModList = $this->modListRepository->find($modListId); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_LIST_DELETE, $subjectModList->getName())); - - $this::assertResponseRedirects(RouteEnum::MOD_LIST_LIST); - - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_LIST_DELETE, $subjectModList->getName())); - - $this::assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND); - } - - /** - * @test - */ - public function deleteAction_authorizedUser_returnsNotFoundResponse(): void - { - $user = $this->userRepository->find(AdminUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_LIST_DELETE, 'non-existing-name')); - - $this::assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND); - } -} diff --git a/tests/functional/Controller/ModList/ListActionTest.php b/tests/functional/Controller/ModList/ListActionTest.php deleted file mode 100644 index ecf342fc..00000000 --- a/tests/functional/Controller/ModList/ListActionTest.php +++ /dev/null @@ -1,68 +0,0 @@ -client = self::createClient(); - $this->userRepository = self::getContainer()->get(UserRepository::class); - } - - /** - * @test - */ - public function listAction_anonymousUser_returnsRedirectResponse(): void - { - $this->client->request(Request::METHOD_GET, RouteEnum::MOD_LIST_LIST); - - $this::assertResponseRedirects(RouteEnum::SECURITY_CONNECT_DISCORD, Response::HTTP_FOUND); - } - - /** - * @test - */ - public function listAction_unauthorizedUser_returnsForbiddenResponse(): void - { - $user = $this->userRepository->find(RegularUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, RouteEnum::MOD_LIST_LIST); - - $this::assertResponseStatusCodeSame(Response::HTTP_FORBIDDEN); - } - - /** - * @test - */ - public function listAction_authorizedUser_returnsSuccessfulResponse(): void - { - $user = $this->userRepository->find(AdminUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, RouteEnum::MOD_LIST_LIST); - - $this::assertResponseStatusCodeSame(Response::HTTP_OK); - } -} diff --git a/tests/functional/Controller/ModListPublic/CustomizeActionTest.php b/tests/functional/Controller/ModListPublic/CustomizeActionTest.php deleted file mode 100644 index 73a79f94..00000000 --- a/tests/functional/Controller/ModListPublic/CustomizeActionTest.php +++ /dev/null @@ -1,66 +0,0 @@ -client = self::createClient(); - $this->userRepository = self::getContainer()->get(UserRepository::class); - $this->modListRepository = self::getContainer()->get(ModListRepository::class); - } - - /** - * @test - * @dataProvider allUserTypesDataProvider - */ - public function customizeAction_authorizedUser_returnsSuccessfulResponse(string $userId): void - { - $user = $this->userRepository->find($userId); - $subjectModList = $this->modListRepository->find(DefaultModListFixture::ID); - - !$user ?: $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_LIST_PUBLIC_CUSTOMIZE, $subjectModList->getName())); - - $this::assertResponseStatusCodeSame(Response::HTTP_OK); - } - - /** - * @test - * @dataProvider allUserTypesDataProvider - */ - public function customizeAction_authorizedUser_returnsNotFoundResponse(string $userId): void - { - $user = $this->userRepository->find($userId); - - !$user ?: $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_LIST_PUBLIC_CUSTOMIZE, 'non-existing-name')); - - $this::assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND); - } -} diff --git a/tests/functional/Controller/ModListPublic/DownloadActionTest.php b/tests/functional/Controller/ModListPublic/DownloadActionTest.php deleted file mode 100644 index 1d40e437..00000000 --- a/tests/functional/Controller/ModListPublic/DownloadActionTest.php +++ /dev/null @@ -1,130 +0,0 @@ -client = self::createClient(); - $this->userRepository = self::getContainer()->get(UserRepository::class); - $this->modListRepository = self::getContainer()->get(ModListRepository::class); - $this->steamWorkshopModRepository = self::getContainer()->get(SteamWorkshopModRepository::class); - } - - /** - * @test - * @dataProvider allUserTypesDataProvider - */ - public function downloadAction_optionalMods_returnsFileResponse(string $userId): void - { - $user = $this->userRepository->find($userId); - $subjectModList = $this->modListRepository->find(DefaultModListFixture::ID); - $optionalMod = $this->steamWorkshopModRepository->find(AceInteractionMenuExpansionModFixture::ID); - - !$user ?: $this->client->loginUser($user); - $crawler = $this->client->request(Request::METHOD_GET, $this->createModListDownloadUrl($subjectModList->getName(), [ - $optionalMod->getId()->toString() => true, - ])); - - $this::assertResponseStatusCodeSame(Response::HTTP_OK); - $this::assertResponseContainsModListAttachmentHeader($this->client->getResponse(), $subjectModList); - $this::assertLauncherPresetContainsMods($crawler, [ - $this->steamWorkshopModRepository->find(Optional\AceInteractionMenuExpansionModFixture::ID), - $this->steamWorkshopModRepository->find(Required\Broken\ArmaForcesAceMedicalModFixture::ID), - $this->steamWorkshopModRepository->find(Required\ArmaForcesModsModFixture::ID), - $this->steamWorkshopModRepository->find(Required\Deprecated\LegacyArmaForcesModsModFixture::ID), - ]); - } - - /** - * @test - * @dataProvider allUserTypesDataProvider - */ - public function downloadAction_requiredMods_returnsFileResponse(string $userId): void - { - $user = $this->userRepository->find($userId); - $subjectModList = $this->modListRepository->find(DefaultModListFixture::ID); - - !$user ?: $this->client->loginUser($user); - $crawler = $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_LIST_PUBLIC_DOWNLOAD, $subjectModList->getName())); - - $this::assertResponseStatusCodeSame(Response::HTTP_OK); - $this::assertResponseContainsModListAttachmentHeader($this->client->getResponse(), $subjectModList); - $this::assertLauncherPresetContainsMods($crawler, [ - $this->steamWorkshopModRepository->find(Required\Broken\ArmaForcesAceMedicalModFixture::ID), - $this->steamWorkshopModRepository->find(Required\ArmaForcesModsModFixture::ID), - $this->steamWorkshopModRepository->find(Required\Deprecated\LegacyArmaForcesModsModFixture::ID), - ]); - } - - /** - * @test - * @dataProvider allUserTypesDataProvider - */ - public function customizeAction_optionalMods_returnsNotFoundResponse(string $userId): void - { - $user = $this->userRepository->find($userId); - $optionalMod = $this->steamWorkshopModRepository->find(AceInteractionMenuExpansionModFixture::ID); - - !$user ?: $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, $this->createModListDownloadUrl('non-existing-name', [ - $optionalMod->getId()->toString() => true, - ])); - - $this::assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND); - } - - /** - * @test - * @dataProvider allUserTypesDataProvider - */ - public function customizeAction_requiredMods_returnsNotFoundResponse(string $userId): void - { - $user = $this->userRepository->find($userId); - - !$user ?: $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_LIST_PUBLIC_DOWNLOAD, 'non-existing-name')); - - $this::assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND); - } - - private function createModListDownloadUrl(string $modListId, array $optionalMods = []): string - { - $url = sprintf(RouteEnum::MOD_LIST_PUBLIC_DOWNLOAD, $modListId); - $optionalModsParameter = $optionalMods ? '/'.json_encode($optionalMods) : ''; - - return $url.$optionalModsParameter; - } -} diff --git a/tests/functional/Controller/ModListPublic/SelectActionTest.php b/tests/functional/Controller/ModListPublic/SelectActionTest.php deleted file mode 100644 index f185875f..00000000 --- a/tests/functional/Controller/ModListPublic/SelectActionTest.php +++ /dev/null @@ -1,47 +0,0 @@ -client = self::createClient(); - $this->userRepository = self::getContainer()->get(UserRepository::class); - } - - /** - * @test - * @dataProvider allUserTypesDataProvider - */ - public function selectAction_authorizedUser_returnsSuccessfulResponse(string $userId): void - { - $user = $this->userRepository->find($userId); - - !$user ?: $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, RouteEnum::MOD_LIST_PUBLIC_SELECT); - - $this::assertResponseStatusCodeSame(Response::HTTP_OK); - } -} diff --git a/tests/functional/Controller/User/DeleteActionTest.php b/tests/functional/Controller/User/DeleteActionTest.php deleted file mode 100644 index c89a2bbd..00000000 --- a/tests/functional/Controller/User/DeleteActionTest.php +++ /dev/null @@ -1,108 +0,0 @@ -client = self::createClient(); - $this->userRepository = self::getContainer()->get(UserRepository::class); - } - - /** - * @test - * @dataProvider registeredUsersDataProvider - */ - public function deleteAction_anonymousUser_returnsRedirectResponse(string $userId): void - { - $subjectUser = $this->userRepository->find($userId); - - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::USER_DELETE, $subjectUser->getId())); - - $this::assertResponseRedirects(RouteEnum::SECURITY_CONNECT_DISCORD, Response::HTTP_FOUND); - } - - /** - * @test - * @dataProvider registeredUsersDataProvider - */ - public function deleteAction_unauthorizedUser_returnsForbiddenResponse(string $userId): void - { - $user = $this->userRepository->find(RegularUserFixture::ID); - $subjectUser = $this->userRepository->find($userId); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::USER_DELETE, $subjectUser->getId())); - - $this::assertResponseStatusCodeSame(Response::HTTP_FORBIDDEN); - } - - /** - * @test - */ - public function deleteAction_authorizedUser_returnsRedirectResponse(): void - { - $user = $this->userRepository->find(AdminUserFixture::ID); - $subjectUser = $this->userRepository->find(RegularUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::USER_DELETE, $subjectUser->getId())); - - $this::assertResponseRedirects(RouteEnum::USER_LIST); - - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::USER_DELETE, $subjectUser->getId())); - - $this::assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND); - } - - /** - * @test - */ - public function deleteAction_authorizedCurrentUser_returnsForbiddenResponse(): void - { - $user = $this->userRepository->find(AdminUserFixture::ID); - $subjectUser = $user; - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::USER_DELETE, $subjectUser->getId())); - - $this::assertResponseStatusCodeSame(Response::HTTP_FORBIDDEN); - } - - /** - * @test - */ - public function deleteAction_authorizedUser_returnsNotFoundResponse(): void - { - $user = $this->userRepository->find(AdminUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::USER_DELETE, 'non-existing-id')); - - $this::assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND); - } -} diff --git a/tests/functional/Controller/User/ListActionTest.php b/tests/functional/Controller/User/ListActionTest.php deleted file mode 100644 index 5d485cee..00000000 --- a/tests/functional/Controller/User/ListActionTest.php +++ /dev/null @@ -1,68 +0,0 @@ -client = self::createClient(); - $this->userRepository = self::getContainer()->get(UserRepository::class); - } - - /** - * @test - */ - public function listAction_anonymousUser_returnsRedirectResponse(): void - { - $this->client->request(Request::METHOD_GET, RouteEnum::USER_LIST); - - $this::assertResponseRedirects(RouteEnum::SECURITY_CONNECT_DISCORD, Response::HTTP_FOUND); - } - - /** - * @test - */ - public function listAction_unauthorizedUser_returnsForbiddenResponse(): void - { - $user = $this->userRepository->find(RegularUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, RouteEnum::USER_LIST); - - $this::assertResponseStatusCodeSame(Response::HTTP_FORBIDDEN); - } - - /** - * @test - */ - public function listAction_authorizedUser_returnsSuccessfulResponse(): void - { - $user = $this->userRepository->find(AdminUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, RouteEnum::USER_LIST); - - $this::assertResponseStatusCodeSame(Response::HTTP_OK); - } -} diff --git a/tests/functional/Controller/User/UpdateActionTest.php b/tests/functional/Controller/User/UpdateActionTest.php deleted file mode 100644 index f23a1ebc..00000000 --- a/tests/functional/Controller/User/UpdateActionTest.php +++ /dev/null @@ -1,91 +0,0 @@ -client = self::createClient(); - $this->userRepository = self::getContainer()->get(UserRepository::class); - } - - /** - * @test - * @dataProvider registeredUsersDataProvider - */ - public function updateAction_anonymousUser_returnsRedirectResponse(string $userId): void - { - $subjectUser = $this->userRepository->find($userId); - - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::USER_UPDATE, $subjectUser->getId())); - - $this::assertResponseRedirects(RouteEnum::SECURITY_CONNECT_DISCORD, Response::HTTP_FOUND); - } - - /** - * @test - * @dataProvider registeredUsersDataProvider - */ - public function updateAction_unauthorizedUser_returnsForbiddenResponse(string $userId): void - { - $user = $this->userRepository->find(RegularUserFixture::ID); - $subjectUser = $this->userRepository->find($userId); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::USER_UPDATE, $subjectUser->getId())); - - $this::assertResponseStatusCodeSame(Response::HTTP_FORBIDDEN); - } - - /** - * @test - * @dataProvider registeredUsersDataProvider - */ - public function updateAction_authorizedUser_returnsSuccessfulResponse(string $userId): void - { - $user = $this->userRepository->find(AdminUserFixture::ID); - $subjectUser = $this->userRepository->find($userId); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::USER_UPDATE, $subjectUser->getId())); - - $this::assertResponseStatusCodeSame(Response::HTTP_OK); - } - - /** - * @test - */ - public function updateAction_authorizedUser_returnsNotFoundResponse(): void - { - $user = $this->userRepository->find(AdminUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::USER_UPDATE, 'non-existing-id')); - - $this::assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND); - } -} diff --git a/tests/functional/Controller/UserGroup/CreateActionTest.php b/tests/functional/Controller/UserGroup/CreateActionTest.php deleted file mode 100644 index 0e8de3e6..00000000 --- a/tests/functional/Controller/UserGroup/CreateActionTest.php +++ /dev/null @@ -1,68 +0,0 @@ -client = self::createClient(); - $this->userRepository = self::getContainer()->get(UserRepository::class); - } - - /** - * @test - */ - public function createAction_anonymousUser_returnsRedirectResponse(): void - { - $this->client->request(Request::METHOD_GET, RouteEnum::USER_GROUP_CREATE); - - $this::assertResponseRedirects(RouteEnum::SECURITY_CONNECT_DISCORD, Response::HTTP_FOUND); - } - - /** - * @test - */ - public function createAction_unauthorizedUser_returnsForbiddenResponse(): void - { - $user = $this->userRepository->find(RegularUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, RouteEnum::USER_GROUP_CREATE); - - $this::assertResponseStatusCodeSame(Response::HTTP_FORBIDDEN); - } - - /** - * @test - */ - public function createAction_authorizedUser_returnsSuccessfulResponse(): void - { - $user = $this->userRepository->find(AdminUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, RouteEnum::USER_GROUP_CREATE); - - $this::assertResponseStatusCodeSame(Response::HTTP_OK); - } -} diff --git a/tests/functional/Controller/UserGroup/DeleteActionTest.php b/tests/functional/Controller/UserGroup/DeleteActionTest.php deleted file mode 100644 index d1f77be8..00000000 --- a/tests/functional/Controller/UserGroup/DeleteActionTest.php +++ /dev/null @@ -1,98 +0,0 @@ -client = self::createClient(); - $this->userRepository = self::getContainer()->get(UserRepository::class); - $this->modGroupRepository = self::getContainer()->get(ModGroupRepository::class); - } - - /** - * @test - * @dataProvider modGroupsDataProvider - */ - public function deleteAction_anonymousUser_returnsRedirectResponse(string $modGroupId): void - { - $subjectModGroup = $this->modGroupRepository->find($modGroupId); - - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_GROUP_DELETE, $subjectModGroup->getName())); - - $this::assertResponseRedirects(RouteEnum::SECURITY_CONNECT_DISCORD, Response::HTTP_FOUND); - } - - /** - * @test - * @dataProvider modGroupsDataProvider - */ - public function deleteAction_unauthorizedUser_returnsForbiddenResponse(string $modGroupId): void - { - $user = $this->userRepository->find(RegularUserFixture::ID); - $subjectModGroup = $this->modGroupRepository->find($modGroupId); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_GROUP_DELETE, $subjectModGroup->getName())); - - $this::assertResponseStatusCodeSame(Response::HTTP_FORBIDDEN); - } - - /** - * @test - * @dataProvider modGroupsDataProvider - */ - public function deleteAction_authorizedUser_returnsSuccessfulResponse(string $modGroupId): void - { - $user = $this->userRepository->find(AdminUserFixture::ID); - $subjectModGroup = $this->modGroupRepository->find($modGroupId); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_GROUP_DELETE, $subjectModGroup->getName())); - - $this::assertResponseRedirects(RouteEnum::MOD_GROUP_LIST); - - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_GROUP_DELETE, $subjectModGroup->getName())); - - $this::assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND); - } - - /** - * @test - */ - public function deleteAction_authorizedUser_returnsNotFoundResponse(): void - { - $user = $this->userRepository->find(AdminUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, sprintf(RouteEnum::MOD_GROUP_DELETE, 'non-existing-name')); - - $this::assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND); - } -} diff --git a/tests/functional/Controller/UserGroup/ListActionTest.php b/tests/functional/Controller/UserGroup/ListActionTest.php deleted file mode 100644 index 32a82b80..00000000 --- a/tests/functional/Controller/UserGroup/ListActionTest.php +++ /dev/null @@ -1,68 +0,0 @@ -client = self::createClient(); - $this->userRepository = self::getContainer()->get(UserRepository::class); - } - - /** - * @test - */ - public function listAction_anonymousUser_returnsRedirectResponse(): void - { - $this->client->request(Request::METHOD_GET, RouteEnum::USER_GROUP_CREATE); - - $this::assertResponseRedirects(RouteEnum::SECURITY_CONNECT_DISCORD, Response::HTTP_FOUND); - } - - /** - * @test - */ - public function listAction_unauthorizedUser_returnsForbiddenResponse(): void - { - $user = $this->userRepository->find(RegularUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, RouteEnum::MOD_GROUP_LIST); - - $this::assertResponseStatusCodeSame(Response::HTTP_FORBIDDEN); - } - - /** - * @test - */ - public function listAction_authorizedUser_returnsSuccessfulResponse(): void - { - $user = $this->userRepository->find(AdminUserFixture::ID); - - $this->client->loginUser($user); - $this->client->request(Request::METHOD_GET, RouteEnum::MOD_GROUP_LIST); - - $this::assertResponseStatusCodeSame(Response::HTTP_OK); - } -} From 08982ce0187a3d9625d8e8acb2206510668328a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Skowro=C5=84ski?= Date: Sat, 13 Jan 2024 15:10:09 +0100 Subject: [PATCH 06/17] Refactor fixtures --- .../Attendance/AttendanceFixtures.php | 43 ++- src/DataFixtures/Dlc/CslaIronCurtain.php | 31 -- .../Dlc/CslaIronCurtainDlcFixture.php | 37 ++ .../Dlc/GlobalMobilizationDlcFixture.php | 37 ++ .../Dlc/GlobalMobilizationFixture.php | 31 -- .../Dlc/SogPrairieFireDlcFixture.php | 37 ++ .../Dlc/SogPrairieFireFixture.php | 31 -- .../Dlc/Spearhead1944DlcFixture.php | 37 ++ src/DataFixtures/Dlc/WesternSaharaFixture.php | 31 -- .../ArmaScriptProfilerModFixture.php | 37 ++ .../Mod/Directory/Deprecated/R3ModFixture.php | 38 +++ .../AceInteractionMenuExpansionModFixture.php | 5 +- .../Required/ArmaForcesMedicalModFixture.php} | 9 +- .../Broken/ArmaForcesAceMedicalModFixture.php | 5 +- .../Required/CupTerrainsCoreModFixture.php | 39 +++ .../Required/CupTerrainsMapsModFixture.php | 39 +++ .../Required/CupUnitsModFixture.php | 39 +++ .../Required/CupVehiclesModFixture.php | 39 +++ .../Required/CupWeaponsModFixture.php | 39 +++ .../LegacyArmaForcesModsModFixture.php | 5 +- .../ArmaForcesJbadBuildingFixModFixture.php | 5 +- .../Required/RhsAfrfModFixture.php | 39 +++ .../Required/RhsGrefModFixture.php | 39 +++ .../Required/RhsUsafModFixture.php | 39 +++ .../ModGroup/CupModGroupFixture.php | 59 ++++ .../ModGroup/RhsModGroupFixture.php | 26 +- .../ModList/CupModListFixture.php | 90 +++++ .../ModList/DefaultModListFixture.php | 101 +++++- .../ModList/RhsModListFixture.php | 90 +++++ src/DataFixtures/User/AdminFixture.php | 47 +++ src/DataFixtures/User/AdminUserFixture.php | 39 --- src/DataFixtures/User/RegularUserFixture.php | 38 --- src/DataFixtures/User/User1Fixture.php | 47 +++ src/DataFixtures/User/User2Fixture.php | 47 +++ src/DataFixtures/User/User3Fixture.php | 47 +++ .../UserGroup/AdminsGroupFixture.php | 52 +++ .../UserGroup/UsersGroupFixture.php | 58 ++++ .../GetPublishedFileDetails/1981535406.json | 41 +++ .../GetPublishedFileDetails/455312245.json | 38 +++ .../Test/data/appdetails/1681170.json | 321 ++++++++++++++++++ .../Test/data/appdetails/2138330.json | 270 +++++++++++++++ .../SteamApiClient/SteamApiClientCest.php | 4 +- 42 files changed, 1906 insertions(+), 240 deletions(-) delete mode 100644 src/DataFixtures/Dlc/CslaIronCurtain.php create mode 100644 src/DataFixtures/Dlc/CslaIronCurtainDlcFixture.php create mode 100644 src/DataFixtures/Dlc/GlobalMobilizationDlcFixture.php delete mode 100644 src/DataFixtures/Dlc/GlobalMobilizationFixture.php create mode 100644 src/DataFixtures/Dlc/SogPrairieFireDlcFixture.php delete mode 100644 src/DataFixtures/Dlc/SogPrairieFireFixture.php create mode 100644 src/DataFixtures/Dlc/Spearhead1944DlcFixture.php delete mode 100644 src/DataFixtures/Dlc/WesternSaharaFixture.php create mode 100644 src/DataFixtures/Mod/Directory/ArmaScriptProfilerModFixture.php create mode 100644 src/DataFixtures/Mod/Directory/Deprecated/R3ModFixture.php rename src/DataFixtures/Mod/{ => SteamWorkshop}/Optional/AceInteractionMenuExpansionModFixture.php (88%) rename src/DataFixtures/Mod/{Required/ArmaForcesModsModFixture.php => SteamWorkshop/Required/ArmaForcesMedicalModFixture.php} (79%) rename src/DataFixtures/Mod/{ => SteamWorkshop}/Required/Broken/ArmaForcesAceMedicalModFixture.php (88%) create mode 100644 src/DataFixtures/Mod/SteamWorkshop/Required/CupTerrainsCoreModFixture.php create mode 100644 src/DataFixtures/Mod/SteamWorkshop/Required/CupTerrainsMapsModFixture.php create mode 100644 src/DataFixtures/Mod/SteamWorkshop/Required/CupUnitsModFixture.php create mode 100644 src/DataFixtures/Mod/SteamWorkshop/Required/CupVehiclesModFixture.php create mode 100644 src/DataFixtures/Mod/SteamWorkshop/Required/CupWeaponsModFixture.php rename src/DataFixtures/Mod/{ => SteamWorkshop}/Required/Deprecated/LegacyArmaForcesModsModFixture.php (87%) rename src/DataFixtures/Mod/{ => SteamWorkshop}/Required/Disabled/ArmaForcesJbadBuildingFixModFixture.php (88%) create mode 100644 src/DataFixtures/Mod/SteamWorkshop/Required/RhsAfrfModFixture.php create mode 100644 src/DataFixtures/Mod/SteamWorkshop/Required/RhsGrefModFixture.php create mode 100644 src/DataFixtures/Mod/SteamWorkshop/Required/RhsUsafModFixture.php create mode 100644 src/DataFixtures/ModGroup/CupModGroupFixture.php create mode 100644 src/DataFixtures/ModList/CupModListFixture.php create mode 100644 src/DataFixtures/ModList/RhsModListFixture.php create mode 100644 src/DataFixtures/User/AdminFixture.php delete mode 100644 src/DataFixtures/User/AdminUserFixture.php delete mode 100644 src/DataFixtures/User/RegularUserFixture.php create mode 100644 src/DataFixtures/User/User1Fixture.php create mode 100644 src/DataFixtures/User/User2Fixture.php create mode 100644 src/DataFixtures/User/User3Fixture.php create mode 100644 src/DataFixtures/UserGroup/AdminsGroupFixture.php create mode 100644 src/DataFixtures/UserGroup/UsersGroupFixture.php create mode 100644 src/Service/SteamApiClient/Test/data/GetPublishedFileDetails/1981535406.json create mode 100644 src/Service/SteamApiClient/Test/data/GetPublishedFileDetails/455312245.json create mode 100644 src/Service/SteamApiClient/Test/data/appdetails/1681170.json create mode 100644 src/Service/SteamApiClient/Test/data/appdetails/2138330.json diff --git a/src/DataFixtures/Attendance/AttendanceFixtures.php b/src/DataFixtures/Attendance/AttendanceFixtures.php index b9f19140..d4da21b9 100644 --- a/src/DataFixtures/Attendance/AttendanceFixtures.php +++ b/src/DataFixtures/Attendance/AttendanceFixtures.php @@ -5,19 +5,54 @@ namespace App\DataFixtures\Attendance; use App\Entity\Attendance\Attendance; +use App\Test\Traits\TimeTrait; use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Persistence\ObjectManager; use Ramsey\Uuid\Uuid; class AttendanceFixtures extends Fixture { + use TimeTrait; + public function load(ObjectManager $manager): void { - for ($i = 1; $i <= 10; ++$i) { - $attendance = new Attendance(Uuid::uuid4(), "mission_{$i}", 76561198048200529); + $this->withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $attendance = new Attendance( + Uuid::fromString('2694264f-0e6f-40a6-9596-bc22d1eaa2c7'), + 'mission_1', + 76561198048200529 + ); + $manager->persist($attendance); + + $attendance = new Attendance( + Uuid::fromString('d2a60cd4-d3f0-497a-9840-69fa5c388f1e'), + 'mission_2', + 76561198048200529 + ); + $manager->persist($attendance); + + $attendance = new Attendance( + Uuid::fromString('0a918bf1-d20f-4856-aa0d-f093f6e90bf7'), + 'mission_3', + 76561198048200529 + ); + $manager->persist($attendance); + + $attendance = new Attendance( + Uuid::fromString('2a3aa170-3a79-471f-b6ec-e194bf8d6c9e'), + 'mission_4', + 76561198048200529 + ); + $manager->persist($attendance); + + $attendance = new Attendance( + Uuid::fromString('ac22546b-9d5c-4a54-a713-01dcc5ee40e6'), + 'mission_5', + 76561198048200529 + ); $manager->persist($attendance); - } - $manager->flush(); + $manager->flush(); + }); } } diff --git a/src/DataFixtures/Dlc/CslaIronCurtain.php b/src/DataFixtures/Dlc/CslaIronCurtain.php deleted file mode 100644 index f581af86..00000000 --- a/src/DataFixtures/Dlc/CslaIronCurtain.php +++ /dev/null @@ -1,31 +0,0 @@ -persist($dlc); - $manager->flush(); - - $this->addReference(self::ID, $dlc); - } -} diff --git a/src/DataFixtures/Dlc/CslaIronCurtainDlcFixture.php b/src/DataFixtures/Dlc/CslaIronCurtainDlcFixture.php new file mode 100644 index 00000000..c288bbd6 --- /dev/null +++ b/src/DataFixtures/Dlc/CslaIronCurtainDlcFixture.php @@ -0,0 +1,37 @@ +withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $dlc = new Dlc( + Uuid::fromString(self::ID), + 'Arma 3 Creator DLC: CSLA Iron Curtain', + null, + self::APP_ID, + 'csla' + ); + + $manager->persist($dlc); + $manager->flush(); + + $this->addReference(self::ID, $dlc); + }); + } +} diff --git a/src/DataFixtures/Dlc/GlobalMobilizationDlcFixture.php b/src/DataFixtures/Dlc/GlobalMobilizationDlcFixture.php new file mode 100644 index 00000000..0118e95b --- /dev/null +++ b/src/DataFixtures/Dlc/GlobalMobilizationDlcFixture.php @@ -0,0 +1,37 @@ +withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $dlc = new Dlc( + Uuid::fromString(self::ID), + 'Arma 3 Creator DLC: Global Mobilization - Cold War Germany', + null, + self::APP_ID, + 'gm' + ); + + $manager->persist($dlc); + $manager->flush(); + + $this->addReference(self::ID, $dlc); + }); + } +} diff --git a/src/DataFixtures/Dlc/GlobalMobilizationFixture.php b/src/DataFixtures/Dlc/GlobalMobilizationFixture.php deleted file mode 100644 index 7da4ee62..00000000 --- a/src/DataFixtures/Dlc/GlobalMobilizationFixture.php +++ /dev/null @@ -1,31 +0,0 @@ -persist($dlc); - $manager->flush(); - - $this->addReference(self::ID, $dlc); - } -} diff --git a/src/DataFixtures/Dlc/SogPrairieFireDlcFixture.php b/src/DataFixtures/Dlc/SogPrairieFireDlcFixture.php new file mode 100644 index 00000000..e28f6052 --- /dev/null +++ b/src/DataFixtures/Dlc/SogPrairieFireDlcFixture.php @@ -0,0 +1,37 @@ +withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $dlc = new Dlc( + Uuid::fromString(self::ID), + 'Arma 3 Creator DLC: S.O.G. Prairie Fire', + null, + self::APP_ID, + 'vn' + ); + + $manager->persist($dlc); + $manager->flush(); + + $this->addReference(self::ID, $dlc); + }); + } +} diff --git a/src/DataFixtures/Dlc/SogPrairieFireFixture.php b/src/DataFixtures/Dlc/SogPrairieFireFixture.php deleted file mode 100644 index be7a9d9f..00000000 --- a/src/DataFixtures/Dlc/SogPrairieFireFixture.php +++ /dev/null @@ -1,31 +0,0 @@ -persist($dlc); - $manager->flush(); - - $this->addReference(self::ID, $dlc); - } -} diff --git a/src/DataFixtures/Dlc/Spearhead1944DlcFixture.php b/src/DataFixtures/Dlc/Spearhead1944DlcFixture.php new file mode 100644 index 00000000..88bddb35 --- /dev/null +++ b/src/DataFixtures/Dlc/Spearhead1944DlcFixture.php @@ -0,0 +1,37 @@ +withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $dlc = new Dlc( + Uuid::fromString(self::ID), + 'Arma 3 Creator DLC: Spearhead 1944', + null, + self::APP_ID, + 'spe' + ); + + $manager->persist($dlc); + $manager->flush(); + + $this->addReference(self::ID, $dlc); + }); + } +} diff --git a/src/DataFixtures/Dlc/WesternSaharaFixture.php b/src/DataFixtures/Dlc/WesternSaharaFixture.php deleted file mode 100644 index 20b69c31..00000000 --- a/src/DataFixtures/Dlc/WesternSaharaFixture.php +++ /dev/null @@ -1,31 +0,0 @@ -persist($dlc); - $manager->flush(); - - $this->addReference(self::ID, $dlc); - } -} diff --git a/src/DataFixtures/Mod/Directory/ArmaScriptProfilerModFixture.php b/src/DataFixtures/Mod/Directory/ArmaScriptProfilerModFixture.php new file mode 100644 index 00000000..f51377df --- /dev/null +++ b/src/DataFixtures/Mod/Directory/ArmaScriptProfilerModFixture.php @@ -0,0 +1,37 @@ +withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $mod = new DirectoryMod( + Uuid::fromString(self::ID), + 'Arma Script Profiler', + null, + null, + self::DIRECTORY + ); + + $manager->persist($mod); + $manager->flush(); + + $this->addReference(self::ID, $mod); + }); + } +} diff --git a/src/DataFixtures/Mod/Directory/Deprecated/R3ModFixture.php b/src/DataFixtures/Mod/Directory/Deprecated/R3ModFixture.php new file mode 100644 index 00000000..87aabec8 --- /dev/null +++ b/src/DataFixtures/Mod/Directory/Deprecated/R3ModFixture.php @@ -0,0 +1,38 @@ +withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $mod = new DirectoryMod( + Uuid::fromString(self::ID), + 'R3', + null, + ModStatusEnum::DEPRECATED, + self::DIRECTORY + ); + + $manager->persist($mod); + $manager->flush(); + + $this->addReference(self::ID, $mod); + }); + } +} diff --git a/src/DataFixtures/Mod/Optional/AceInteractionMenuExpansionModFixture.php b/src/DataFixtures/Mod/SteamWorkshop/Optional/AceInteractionMenuExpansionModFixture.php similarity index 88% rename from src/DataFixtures/Mod/Optional/AceInteractionMenuExpansionModFixture.php rename to src/DataFixtures/Mod/SteamWorkshop/Optional/AceInteractionMenuExpansionModFixture.php index bcc8aea4..667baaec 100644 --- a/src/DataFixtures/Mod/Optional/AceInteractionMenuExpansionModFixture.php +++ b/src/DataFixtures/Mod/SteamWorkshop/Optional/AceInteractionMenuExpansionModFixture.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\DataFixtures\Mod\Optional; +namespace App\DataFixtures\Mod\SteamWorkshop\Optional; use App\Entity\Mod\Enum\ModTypeEnum; use App\Entity\Mod\SteamWorkshopMod; @@ -16,6 +16,7 @@ class AceInteractionMenuExpansionModFixture extends Fixture use TimeTrait; public const ID = '37f58e30-5194-4594-89af-4a82c7fc02be'; + public const ITEM_ID = 1376867375; public function load(ObjectManager $manager): void { @@ -26,7 +27,7 @@ public function load(ObjectManager $manager): void null, null, ModTypeEnum::OPTIONAL, - 1376867375 + self::ITEM_ID ); $manager->persist($mod); diff --git a/src/DataFixtures/Mod/Required/ArmaForcesModsModFixture.php b/src/DataFixtures/Mod/SteamWorkshop/Required/ArmaForcesMedicalModFixture.php similarity index 79% rename from src/DataFixtures/Mod/Required/ArmaForcesModsModFixture.php rename to src/DataFixtures/Mod/SteamWorkshop/Required/ArmaForcesMedicalModFixture.php index bcbf0db7..c8516acc 100644 --- a/src/DataFixtures/Mod/Required/ArmaForcesModsModFixture.php +++ b/src/DataFixtures/Mod/SteamWorkshop/Required/ArmaForcesMedicalModFixture.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\DataFixtures\Mod\Required; +namespace App\DataFixtures\Mod\SteamWorkshop\Required; use App\Entity\Mod\Enum\ModTypeEnum; use App\Entity\Mod\SteamWorkshopMod; @@ -11,22 +11,23 @@ use Doctrine\Persistence\ObjectManager; use Ramsey\Uuid\Uuid; -class ArmaForcesModsModFixture extends Fixture +class ArmaForcesMedicalModFixture extends Fixture { use TimeTrait; public const ID = '0e4e059c-eef6-42a9-aec3-abdab344ec21'; + public const ITEM_ID = 1981535406; public function load(ObjectManager $manager): void { $this->withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { $mod = new SteamWorkshopMod( Uuid::fromString(self::ID), - 'ArmaForces - Mods', + 'ArmaForces - Medical', null, null, ModTypeEnum::REQUIRED, - 1934142795 + self::ITEM_ID ); $manager->persist($mod); diff --git a/src/DataFixtures/Mod/Required/Broken/ArmaForcesAceMedicalModFixture.php b/src/DataFixtures/Mod/SteamWorkshop/Required/Broken/ArmaForcesAceMedicalModFixture.php similarity index 88% rename from src/DataFixtures/Mod/Required/Broken/ArmaForcesAceMedicalModFixture.php rename to src/DataFixtures/Mod/SteamWorkshop/Required/Broken/ArmaForcesAceMedicalModFixture.php index 4c3ebfba..3165a073 100644 --- a/src/DataFixtures/Mod/Required/Broken/ArmaForcesAceMedicalModFixture.php +++ b/src/DataFixtures/Mod/SteamWorkshop/Required/Broken/ArmaForcesAceMedicalModFixture.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\DataFixtures\Mod\Required\Broken; +namespace App\DataFixtures\Mod\SteamWorkshop\Required\Broken; use App\Entity\Mod\Enum\ModStatusEnum; use App\Entity\Mod\Enum\ModTypeEnum; @@ -17,6 +17,7 @@ class ArmaForcesAceMedicalModFixture extends Fixture use TimeTrait; public const ID = '2f1d2dea-a7a6-4509-b478-66a980d724ca'; + public const ITEM_ID = 1704054308; public function load(ObjectManager $manager): void { @@ -27,7 +28,7 @@ public function load(ObjectManager $manager): void null, ModStatusEnum::BROKEN, ModTypeEnum::REQUIRED, - 1704054308 + self::ITEM_ID ); $manager->persist($mod); diff --git a/src/DataFixtures/Mod/SteamWorkshop/Required/CupTerrainsCoreModFixture.php b/src/DataFixtures/Mod/SteamWorkshop/Required/CupTerrainsCoreModFixture.php new file mode 100644 index 00000000..6d1997f7 --- /dev/null +++ b/src/DataFixtures/Mod/SteamWorkshop/Required/CupTerrainsCoreModFixture.php @@ -0,0 +1,39 @@ +withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $mod = new SteamWorkshopMod( + Uuid::fromString(self::ID), + 'CUP Terrains - Core', + null, + null, + ModTypeEnum::REQUIRED, + self::ITEM_ID + ); + + $manager->persist($mod); + $manager->flush(); + + $this->addReference(self::ID, $mod); + }); + } +} diff --git a/src/DataFixtures/Mod/SteamWorkshop/Required/CupTerrainsMapsModFixture.php b/src/DataFixtures/Mod/SteamWorkshop/Required/CupTerrainsMapsModFixture.php new file mode 100644 index 00000000..c3cc41c3 --- /dev/null +++ b/src/DataFixtures/Mod/SteamWorkshop/Required/CupTerrainsMapsModFixture.php @@ -0,0 +1,39 @@ +withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $mod = new SteamWorkshopMod( + Uuid::fromString(self::ID), + 'CUP Terrains - Maps', + null, + null, + ModTypeEnum::REQUIRED, + self::ITEM_ID + ); + + $manager->persist($mod); + $manager->flush(); + + $this->addReference(self::ID, $mod); + }); + } +} diff --git a/src/DataFixtures/Mod/SteamWorkshop/Required/CupUnitsModFixture.php b/src/DataFixtures/Mod/SteamWorkshop/Required/CupUnitsModFixture.php new file mode 100644 index 00000000..5b6a64d1 --- /dev/null +++ b/src/DataFixtures/Mod/SteamWorkshop/Required/CupUnitsModFixture.php @@ -0,0 +1,39 @@ +withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $mod = new SteamWorkshopMod( + Uuid::fromString(self::ID), + 'CUP Units', + null, + null, + ModTypeEnum::REQUIRED, + self::ITEM_ID + ); + + $manager->persist($mod); + $manager->flush(); + + $this->addReference(self::ID, $mod); + }); + } +} diff --git a/src/DataFixtures/Mod/SteamWorkshop/Required/CupVehiclesModFixture.php b/src/DataFixtures/Mod/SteamWorkshop/Required/CupVehiclesModFixture.php new file mode 100644 index 00000000..1cf0f7e0 --- /dev/null +++ b/src/DataFixtures/Mod/SteamWorkshop/Required/CupVehiclesModFixture.php @@ -0,0 +1,39 @@ +withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $mod = new SteamWorkshopMod( + Uuid::fromString(self::ID), + 'CUP Vehicles', + null, + null, + ModTypeEnum::REQUIRED, + self::ITEM_ID + ); + + $manager->persist($mod); + $manager->flush(); + + $this->addReference(self::ID, $mod); + }); + } +} diff --git a/src/DataFixtures/Mod/SteamWorkshop/Required/CupWeaponsModFixture.php b/src/DataFixtures/Mod/SteamWorkshop/Required/CupWeaponsModFixture.php new file mode 100644 index 00000000..04e763b0 --- /dev/null +++ b/src/DataFixtures/Mod/SteamWorkshop/Required/CupWeaponsModFixture.php @@ -0,0 +1,39 @@ +withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $mod = new SteamWorkshopMod( + Uuid::fromString(self::ID), + 'CUP Weapons', + null, + null, + ModTypeEnum::REQUIRED, + self::ITEM_ID + ); + + $manager->persist($mod); + $manager->flush(); + + $this->addReference(self::ID, $mod); + }); + } +} diff --git a/src/DataFixtures/Mod/Required/Deprecated/LegacyArmaForcesModsModFixture.php b/src/DataFixtures/Mod/SteamWorkshop/Required/Deprecated/LegacyArmaForcesModsModFixture.php similarity index 87% rename from src/DataFixtures/Mod/Required/Deprecated/LegacyArmaForcesModsModFixture.php rename to src/DataFixtures/Mod/SteamWorkshop/Required/Deprecated/LegacyArmaForcesModsModFixture.php index 0980bed4..c5c34326 100644 --- a/src/DataFixtures/Mod/Required/Deprecated/LegacyArmaForcesModsModFixture.php +++ b/src/DataFixtures/Mod/SteamWorkshop/Required/Deprecated/LegacyArmaForcesModsModFixture.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\DataFixtures\Mod\Required\Deprecated; +namespace App\DataFixtures\Mod\SteamWorkshop\Required\Deprecated; use App\Entity\Mod\Enum\ModStatusEnum; use App\Entity\Mod\Enum\ModTypeEnum; @@ -17,6 +17,7 @@ class LegacyArmaForcesModsModFixture extends Fixture use TimeTrait; public const ID = '7e11c37e-930e-49e8-a87d-8f942d98edb0'; + public const ITEM_ID = 1639399387; public function load(ObjectManager $manager): void { @@ -27,7 +28,7 @@ public function load(ObjectManager $manager): void null, ModStatusEnum::DEPRECATED, ModTypeEnum::REQUIRED, - 1639399387 + self::ITEM_ID ); $manager->persist($mod); diff --git a/src/DataFixtures/Mod/Required/Disabled/ArmaForcesJbadBuildingFixModFixture.php b/src/DataFixtures/Mod/SteamWorkshop/Required/Disabled/ArmaForcesJbadBuildingFixModFixture.php similarity index 88% rename from src/DataFixtures/Mod/Required/Disabled/ArmaForcesJbadBuildingFixModFixture.php rename to src/DataFixtures/Mod/SteamWorkshop/Required/Disabled/ArmaForcesJbadBuildingFixModFixture.php index a1aca103..cc18ac15 100644 --- a/src/DataFixtures/Mod/Required/Disabled/ArmaForcesJbadBuildingFixModFixture.php +++ b/src/DataFixtures/Mod/SteamWorkshop/Required/Disabled/ArmaForcesJbadBuildingFixModFixture.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\DataFixtures\Mod\Required\Disabled; +namespace App\DataFixtures\Mod\SteamWorkshop\Required\Disabled; use App\Entity\Mod\Enum\ModStatusEnum; use App\Entity\Mod\Enum\ModTypeEnum; @@ -17,6 +17,7 @@ class ArmaForcesJbadBuildingFixModFixture extends Fixture use TimeTrait; public const ID = 'b8e88103-69d2-438b-8d89-933ccfdb3a5a'; + public const ITEM_ID = 1781106281; public function load(ObjectManager $manager): void { @@ -27,7 +28,7 @@ public function load(ObjectManager $manager): void null, ModStatusEnum::DISABLED, ModTypeEnum::REQUIRED, - 1781106281 + self::ITEM_ID ); $manager->persist($mod); diff --git a/src/DataFixtures/Mod/SteamWorkshop/Required/RhsAfrfModFixture.php b/src/DataFixtures/Mod/SteamWorkshop/Required/RhsAfrfModFixture.php new file mode 100644 index 00000000..b848526d --- /dev/null +++ b/src/DataFixtures/Mod/SteamWorkshop/Required/RhsAfrfModFixture.php @@ -0,0 +1,39 @@ +withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $mod = new SteamWorkshopMod( + Uuid::fromString(self::ID), + 'RHS AFRF', + null, + null, + ModTypeEnum::REQUIRED, + self::ITEM_ID + ); + + $manager->persist($mod); + $manager->flush(); + + $this->addReference(self::ID, $mod); + }); + } +} diff --git a/src/DataFixtures/Mod/SteamWorkshop/Required/RhsGrefModFixture.php b/src/DataFixtures/Mod/SteamWorkshop/Required/RhsGrefModFixture.php new file mode 100644 index 00000000..2e8364ad --- /dev/null +++ b/src/DataFixtures/Mod/SteamWorkshop/Required/RhsGrefModFixture.php @@ -0,0 +1,39 @@ +withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $mod = new SteamWorkshopMod( + Uuid::fromString(self::ID), + 'RHS GREF', + null, + null, + ModTypeEnum::REQUIRED, + self::ITEM_ID + ); + + $manager->persist($mod); + $manager->flush(); + + $this->addReference(self::ID, $mod); + }); + } +} diff --git a/src/DataFixtures/Mod/SteamWorkshop/Required/RhsUsafModFixture.php b/src/DataFixtures/Mod/SteamWorkshop/Required/RhsUsafModFixture.php new file mode 100644 index 00000000..d8cba558 --- /dev/null +++ b/src/DataFixtures/Mod/SteamWorkshop/Required/RhsUsafModFixture.php @@ -0,0 +1,39 @@ +withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $mod = new SteamWorkshopMod( + Uuid::fromString(self::ID), + 'RHS USAF', + null, + null, + ModTypeEnum::REQUIRED, + self::ITEM_ID + ); + + $manager->persist($mod); + $manager->flush(); + + $this->addReference(self::ID, $mod); + }); + } +} diff --git a/src/DataFixtures/ModGroup/CupModGroupFixture.php b/src/DataFixtures/ModGroup/CupModGroupFixture.php new file mode 100644 index 00000000..0e7525b4 --- /dev/null +++ b/src/DataFixtures/ModGroup/CupModGroupFixture.php @@ -0,0 +1,59 @@ +withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $modGroup = new ModGroup( + Uuid::fromString(self::ID), + self::NAME, + null, + [ + $this->getReference(CupTerrainsCoreModFixture::ID), + $this->getReference(CupTerrainsMapsModFixture::ID), + $this->getReference(CupUnitsModFixture::ID), + $this->getReference(CupVehiclesModFixture::ID), + $this->getReference(CupWeaponsModFixture::ID), + ] + ); + + $manager->persist($modGroup); + $manager->flush(); + + $this->addReference(self::ID, $modGroup); + }); + } + + public function getDependencies(): array + { + return [ + CupTerrainsCoreModFixture::class, + CupTerrainsMapsModFixture::class, + CupUnitsModFixture::class, + CupVehiclesModFixture::class, + CupWeaponsModFixture::class, + ]; + } +} diff --git a/src/DataFixtures/ModGroup/RhsModGroupFixture.php b/src/DataFixtures/ModGroup/RhsModGroupFixture.php index 74f06b1b..2d6629f6 100644 --- a/src/DataFixtures/ModGroup/RhsModGroupFixture.php +++ b/src/DataFixtures/ModGroup/RhsModGroupFixture.php @@ -4,26 +4,35 @@ namespace App\DataFixtures\ModGroup; +use App\DataFixtures\Mod\SteamWorkshop\Required\RhsAfrfModFixture; +use App\DataFixtures\Mod\SteamWorkshop\Required\RhsGrefModFixture; +use App\DataFixtures\Mod\SteamWorkshop\Required\RhsUsafModFixture; use App\Entity\ModGroup\ModGroup; use App\Test\Traits\TimeTrait; use Doctrine\Bundle\FixturesBundle\Fixture; +use Doctrine\Common\DataFixtures\DependentFixtureInterface; use Doctrine\Persistence\ObjectManager; use Ramsey\Uuid\Uuid; -class RhsModGroupFixture extends Fixture +class RhsModGroupFixture extends Fixture implements DependentFixtureInterface { use TimeTrait; - public const ID = '2f183e71-30c1-41c5-a555-acdf5fcf559e'; + public const ID = '33191331-2a40-4d95-ba18-d4a75b1d43d4'; + public const NAME = 'RHS'; public function load(ObjectManager $manager): void { $this->withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { $modGroup = new ModGroup( Uuid::fromString(self::ID), - 'RHS', + self::NAME, null, - [] + [ + $this->getReference(RhsAfrfModFixture::ID), + $this->getReference(RhsGrefModFixture::ID), + $this->getReference(RhsUsafModFixture::ID), + ] ); $manager->persist($modGroup); @@ -32,4 +41,13 @@ public function load(ObjectManager $manager): void $this->addReference(self::ID, $modGroup); }); } + + public function getDependencies(): array + { + return [ + RhsAfrfModFixture::class, + RhsGrefModFixture::class, + RhsUsafModFixture::class, + ]; + } } diff --git a/src/DataFixtures/ModList/CupModListFixture.php b/src/DataFixtures/ModList/CupModListFixture.php new file mode 100644 index 00000000..4a2950d2 --- /dev/null +++ b/src/DataFixtures/ModList/CupModListFixture.php @@ -0,0 +1,90 @@ +withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $owner = $this->getReference(self::OWNER_ID); + + $modList = new ModList( + Uuid::fromString(self::ID), + self::NAME, + null, + [ + $this->getReference(R3ModFixture::ID), + $this->getReference(ArmaScriptProfilerModFixture::ID), + + $this->getReference(AceInteractionMenuExpansionModFixture::ID), + $this->getReference(ArmaForcesAceMedicalModFixture::ID), + $this->getReference(LegacyArmaForcesModsModFixture::ID), + $this->getReference(ArmaForcesJbadBuildingFixModFixture::ID), + $this->getReference(ArmaForcesMedicalModFixture::ID), + ], + [ + $this->getReference(CupModGroupFixture::ID), + ], + [ + $this->getReference(CslaIronCurtainDlcFixture::ID), + ], + $owner, + true, + false, + ); + + $modList->created($owner); + + $manager->persist($modList); + $manager->flush(); + + $this->addReference(self::ID, $modList); + }); + } + + public function getDependencies(): array + { + return [ + User1Fixture::class, // owner + + R3ModFixture::class, + ArmaScriptProfilerModFixture::class, + + AceInteractionMenuExpansionModFixture::class, + ArmaForcesAceMedicalModFixture::class, + LegacyArmaForcesModsModFixture::class, + ArmaForcesJbadBuildingFixModFixture::class, + ArmaForcesMedicalModFixture::class, + + CupModGroupFixture::class, + + CslaIronCurtainDlcFixture::class, + ]; + } +} diff --git a/src/DataFixtures/ModList/DefaultModListFixture.php b/src/DataFixtures/ModList/DefaultModListFixture.php index 8896b76c..90b0046e 100644 --- a/src/DataFixtures/ModList/DefaultModListFixture.php +++ b/src/DataFixtures/ModList/DefaultModListFixture.php @@ -4,41 +4,81 @@ namespace App\DataFixtures\ModList; -use App\DataFixtures\Mod\Optional; -use App\DataFixtures\Mod\Required; +use App\DataFixtures\Dlc\CslaIronCurtainDlcFixture; +use App\DataFixtures\Dlc\GlobalMobilizationDlcFixture; +use App\DataFixtures\Dlc\SogPrairieFireDlcFixture; +use App\DataFixtures\Dlc\Spearhead1944DlcFixture; +use App\DataFixtures\Mod\Directory\ArmaScriptProfilerModFixture; +use App\DataFixtures\Mod\Directory\Deprecated\R3ModFixture; +use App\DataFixtures\Mod\SteamWorkshop\Optional\AceInteractionMenuExpansionModFixture; +use App\DataFixtures\Mod\SteamWorkshop\Required\ArmaForcesMedicalModFixture; +use App\DataFixtures\Mod\SteamWorkshop\Required\Broken\ArmaForcesAceMedicalModFixture; +use App\DataFixtures\Mod\SteamWorkshop\Required\CupTerrainsCoreModFixture; +use App\DataFixtures\Mod\SteamWorkshop\Required\CupTerrainsMapsModFixture; +use App\DataFixtures\Mod\SteamWorkshop\Required\CupUnitsModFixture; +use App\DataFixtures\Mod\SteamWorkshop\Required\CupVehiclesModFixture; +use App\DataFixtures\Mod\SteamWorkshop\Required\CupWeaponsModFixture; +use App\DataFixtures\Mod\SteamWorkshop\Required\Deprecated\LegacyArmaForcesModsModFixture; +use App\DataFixtures\Mod\SteamWorkshop\Required\Disabled\ArmaForcesJbadBuildingFixModFixture; +use App\DataFixtures\Mod\SteamWorkshop\Required\RhsAfrfModFixture; +use App\DataFixtures\Mod\SteamWorkshop\Required\RhsGrefModFixture; +use App\DataFixtures\Mod\SteamWorkshop\Required\RhsUsafModFixture; +use App\DataFixtures\ModGroup\CupModGroupFixture; +use App\DataFixtures\ModGroup\RhsModGroupFixture; use App\Entity\ModList\ModList; use App\Test\Traits\TimeTrait; use Doctrine\Bundle\FixturesBundle\Fixture; +use Doctrine\Common\DataFixtures\DependentFixtureInterface; use Doctrine\Persistence\ObjectManager; use Ramsey\Uuid\Uuid; -class DefaultModListFixture extends Fixture +class DefaultModListFixture extends Fixture implements DependentFixtureInterface { use TimeTrait; public const ID = 'f3e04dae-18a8-4533-99ea-d6d763ebabcf'; + public const NAME = 'Default'; public function load(ObjectManager $manager): void { - $mods = [ - $this->getReference(Optional\AceInteractionMenuExpansionModFixture::ID), - $this->getReference(Required\ArmaForcesModsModFixture::ID), - $this->getReference(Required\Broken\ArmaForcesAceMedicalModFixture::ID), - $this->getReference(Required\Deprecated\LegacyArmaForcesModsModFixture::ID), - $this->getReference(Required\Disabled\ArmaForcesJbadBuildingFixModFixture::ID), - ]; - - $this->withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager, $mods): void { + $this->withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { $modList = new ModList( Uuid::fromString(self::ID), - 'Default', + self::NAME, null, - $mods, - [], - [], + [ + $this->getReference(R3ModFixture::ID), + $this->getReference(ArmaScriptProfilerModFixture::ID), + + $this->getReference(AceInteractionMenuExpansionModFixture::ID), + $this->getReference(ArmaForcesAceMedicalModFixture::ID), + $this->getReference(LegacyArmaForcesModsModFixture::ID), + $this->getReference(ArmaForcesJbadBuildingFixModFixture::ID), + $this->getReference(ArmaForcesMedicalModFixture::ID), + + $this->getReference(CupTerrainsCoreModFixture::ID), + $this->getReference(CupTerrainsMapsModFixture::ID), + $this->getReference(CupUnitsModFixture::ID), + $this->getReference(CupVehiclesModFixture::ID), + $this->getReference(CupWeaponsModFixture::ID), + + $this->getReference(RhsAfrfModFixture::ID), + $this->getReference(RhsGrefModFixture::ID), + $this->getReference(RhsUsafModFixture::ID), + ], + [ + $this->getReference(CupModGroupFixture::ID), + $this->getReference(RhsModGroupFixture::ID), + ], + [ + $this->getReference(CslaIronCurtainDlcFixture::ID), + $this->getReference(GlobalMobilizationDlcFixture::ID), + $this->getReference(SogPrairieFireDlcFixture::ID), + $this->getReference(Spearhead1944DlcFixture::ID), + ], null, true, - false, + true, ); $manager->persist($modList); @@ -47,4 +87,31 @@ public function load(ObjectManager $manager): void $this->addReference(self::ID, $modList); }); } + + public function getDependencies(): array + { + return [ + R3ModFixture::class, + ArmaScriptProfilerModFixture::class, + + AceInteractionMenuExpansionModFixture::class, + ArmaForcesAceMedicalModFixture::class, + LegacyArmaForcesModsModFixture::class, + ArmaForcesJbadBuildingFixModFixture::class, + ArmaForcesMedicalModFixture::class, + + CupTerrainsCoreModFixture::class, + CupTerrainsMapsModFixture::class, + CupUnitsModFixture::class, + CupVehiclesModFixture::class, + CupWeaponsModFixture::class, + + CupModGroupFixture::class, + + CslaIronCurtainDlcFixture::class, + GlobalMobilizationDlcFixture::class, + SogPrairieFireDlcFixture::class, + Spearhead1944DlcFixture::class, + ]; + } } diff --git a/src/DataFixtures/ModList/RhsModListFixture.php b/src/DataFixtures/ModList/RhsModListFixture.php new file mode 100644 index 00000000..887fcaa2 --- /dev/null +++ b/src/DataFixtures/ModList/RhsModListFixture.php @@ -0,0 +1,90 @@ +withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $owner = $this->getReference(self::OWNER_ID); + + $modList = new ModList( + Uuid::fromString(self::ID), + self::NAME, + null, + [ + $this->getReference(R3ModFixture::ID), + $this->getReference(ArmaScriptProfilerModFixture::ID), + + $this->getReference(AceInteractionMenuExpansionModFixture::ID), + $this->getReference(ArmaForcesAceMedicalModFixture::ID), + $this->getReference(LegacyArmaForcesModsModFixture::ID), + $this->getReference(ArmaForcesJbadBuildingFixModFixture::ID), + $this->getReference(ArmaForcesMedicalModFixture::ID), + ], + [ + $this->getReference(RhsModGroupFixture::ID), + ], + [ + $this->getReference(CslaIronCurtainDlcFixture::ID), + ], + $owner, + false, + false, + ); + + $modList->created($owner); + + $manager->persist($modList); + $manager->flush(); + + $this->addReference(self::ID, $modList); + }); + } + + public function getDependencies(): array + { + return [ + User2Fixture::class, // owner + + R3ModFixture::class, + ArmaScriptProfilerModFixture::class, + + AceInteractionMenuExpansionModFixture::class, + ArmaForcesAceMedicalModFixture::class, + LegacyArmaForcesModsModFixture::class, + ArmaForcesJbadBuildingFixModFixture::class, + ArmaForcesMedicalModFixture::class, + + RhsModGroupFixture::class, + + CslaIronCurtainDlcFixture::class, + ]; + } +} diff --git a/src/DataFixtures/User/AdminFixture.php b/src/DataFixtures/User/AdminFixture.php new file mode 100644 index 00000000..81562d1f --- /dev/null +++ b/src/DataFixtures/User/AdminFixture.php @@ -0,0 +1,47 @@ +withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $permissions = new UserPermissions(Uuid::fromString('22dcc83c-8e72-48e4-8b04-debb6fbdd1c8')); + $permissions->grantAll(); + + $user = new User( + Uuid::fromString(self::ID), + self::USERNAME, + self::EMAIL, + self::EXTERNAL_ID, + $permissions, + [], + null, + null + ); + + $manager->persist($permissions); + $manager->persist($user); + $manager->flush(); + + $this->addReference(self::ID, $user); + }); + } +} diff --git a/src/DataFixtures/User/AdminUserFixture.php b/src/DataFixtures/User/AdminUserFixture.php deleted file mode 100644 index 688b3b16..00000000 --- a/src/DataFixtures/User/AdminUserFixture.php +++ /dev/null @@ -1,39 +0,0 @@ -grantAll(); - - $user = new User( - Uuid::fromString(self::ID), - 'admin#1111', - 'admin@example.com', - self::ID, - $permissions, - [], - null, - null - ); - - $manager->persist($permissions); - $manager->persist($user); - $manager->flush(); - - $this->addReference(self::ID, $user); - } -} diff --git a/src/DataFixtures/User/RegularUserFixture.php b/src/DataFixtures/User/RegularUserFixture.php deleted file mode 100644 index 0b45ed64..00000000 --- a/src/DataFixtures/User/RegularUserFixture.php +++ /dev/null @@ -1,38 +0,0 @@ -persist($permissions); - $manager->persist($user); - $manager->flush(); - - $this->addReference(self::ID, $user); - } -} diff --git a/src/DataFixtures/User/User1Fixture.php b/src/DataFixtures/User/User1Fixture.php new file mode 100644 index 00000000..85e8716c --- /dev/null +++ b/src/DataFixtures/User/User1Fixture.php @@ -0,0 +1,47 @@ +withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $permissions = new UserPermissions(Uuid::fromString('b62733f6-97dc-4031-b74a-ecb080c09658')); + + $user = new User( + Uuid::fromString(self::ID), + self::USERNAME, + self::EMAIL, + self::EXTERNAL_ID, + $permissions, + [], + null, + self::STEAM_ID + ); + + $manager->persist($permissions); + $manager->persist($user); + $manager->flush(); + + $this->addReference(self::ID, $user); + }); + } +} diff --git a/src/DataFixtures/User/User2Fixture.php b/src/DataFixtures/User/User2Fixture.php new file mode 100644 index 00000000..bd5d6c22 --- /dev/null +++ b/src/DataFixtures/User/User2Fixture.php @@ -0,0 +1,47 @@ +withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $permissions = new UserPermissions(Uuid::fromString('97f1c390-46e8-47cd-b60d-e9cca1ae892e')); + + $user = new User( + Uuid::fromString(self::ID), + self::USERNAME, + self::EMAIL, + self::EXTERNAL_ID, + $permissions, + [], + null, + self::STEAM_ID + ); + + $manager->persist($permissions); + $manager->persist($user); + $manager->flush(); + + $this->addReference(self::ID, $user); + }); + } +} diff --git a/src/DataFixtures/User/User3Fixture.php b/src/DataFixtures/User/User3Fixture.php new file mode 100644 index 00000000..eefdcfea --- /dev/null +++ b/src/DataFixtures/User/User3Fixture.php @@ -0,0 +1,47 @@ +withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $permissions = new UserPermissions(Uuid::fromString('7dcfba43-a09c-46c0-9dbd-701442bd4f83')); + + $user = new User( + Uuid::fromString(self::ID), + self::USERNAME, + self::EMAIL, + self::EXTERNAL_ID, + $permissions, + [], + null, + self::STEAM_ID + ); + + $manager->persist($permissions); + $manager->persist($user); + $manager->flush(); + + $this->addReference(self::ID, $user); + }); + } +} diff --git a/src/DataFixtures/UserGroup/AdminsGroupFixture.php b/src/DataFixtures/UserGroup/AdminsGroupFixture.php new file mode 100644 index 00000000..1567a9e8 --- /dev/null +++ b/src/DataFixtures/UserGroup/AdminsGroupFixture.php @@ -0,0 +1,52 @@ +withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $permissions = new UserGroupPermissions(Uuid::fromString('c5b9af26-29e0-41f5-828f-00563f875d6e')); + + $userGroup = new UserGroup( + Uuid::fromString(self::ID), + self::NAME, + null, + $permissions, + [ + $this->getReference(AdminFixture::ID), + ] + ); + + $manager->persist($permissions); + $manager->persist($userGroup); + $manager->flush(); + + $this->addReference(self::ID, $userGroup); + }); + } + + public function getDependencies(): array + { + return [ + AdminFixture::class, + ]; + } +} diff --git a/src/DataFixtures/UserGroup/UsersGroupFixture.php b/src/DataFixtures/UserGroup/UsersGroupFixture.php new file mode 100644 index 00000000..d392d57e --- /dev/null +++ b/src/DataFixtures/UserGroup/UsersGroupFixture.php @@ -0,0 +1,58 @@ +withTimeFrozenAt('2020-01-01T00:00:00+00:00', function () use ($manager): void { + $permissions = new UserGroupPermissions(Uuid::fromString('323ebe3d-4f20-404e-9b92-c1833405947a')); + + $userGroup = new UserGroup( + Uuid::fromString(self::ID), + self::NAME, + null, + $permissions, + [ + $this->getReference(User1Fixture::ID), + $this->getReference(User2Fixture::ID), + $this->getReference(User3Fixture::ID), + ] + ); + + $manager->persist($permissions); + $manager->persist($userGroup); + $manager->flush(); + + $this->addReference(self::ID, $userGroup); + }); + } + + public function getDependencies(): array + { + return [ + User1Fixture::class, + User2Fixture::class, + User3Fixture::class, + ]; + } +} diff --git a/src/Service/SteamApiClient/Test/data/GetPublishedFileDetails/1981535406.json b/src/Service/SteamApiClient/Test/data/GetPublishedFileDetails/1981535406.json new file mode 100644 index 00000000..4c550df7 --- /dev/null +++ b/src/Service/SteamApiClient/Test/data/GetPublishedFileDetails/1981535406.json @@ -0,0 +1,41 @@ +{ + "response": { + "result": 1, + "resultcount": 1, + "publishedfiledetails": [ + { + "publishedfileid": "1981535406", + "result": 1, + "creator": "76561199002669156", + "creator_app_id": 107410, + "consumer_app_id": 107410, + "filename": "", + "file_size": 295103, + "file_url": "", + "hcontent_file": "6332893528122366633", + "preview_url": "https://steamuserimages-a.akamaihd.net/ugc/772868569532489292/64412B75F35CB6E699F5B132441B4894AC10778E/", + "hcontent_preview": "772868569532489292", + "title": "ArmaForces - Medical", + "description": "[h1]Introducing ArmaForces Medical System.[/h1]\r\n- More efficient bandaging\r\n- Bandages are more durable, stay for even 30 minutes if applied right bandage on correct wound!\r\n- All medical actions take less time to complete\r\n- New pain fighting medication - Apap - with no side effects!\r\n\r\n[h2]Decreased treatment times[/h2]\r\n- Bandaging time / 2\r\n- Applying Tourniquet 7 -> 2.5 s\r\n- Removing Tourniquet 7 -> 1.5 s\r\n- Splint 7 -> 5 s\r\n- IV 12 -> 5 s\r\n\r\n[h2]Reworked bandages[/h2]\r\n- All bandages are at least 2-3 times more efficient than in standard ACE\r\n- 3 types of efficiency (standard ACE bandages are maximum at 2)\r\n - Super - 10-8 base efficiency\r\n - Increased - 6-4 base efficiency\r\n - Standard - 2-4 base efficiency\r\n- Much longer wound opening times, especially for super efficiency\r\n - Super - 10% opening chance, 10-30 minutes durability\r\n - Increased - 30% opening chance, 6-20 minutes\r\n - Standard - 40% opening chance, 5-10 minutes\r\n\r\n[h2]Pain fighting medication (Apap) without side effects[/h2]\r\n- A bit weaker than morphine (0.6 vs 0.8 pain fighting force)\r\n- Effect lasts for up to 10 minutes (vs 30 for morphine)\r\n- Only for conscious units (so morphine is still viable)\r\n\r\n[h1]Future plans:[/h1]\r\nWe first want to adjust mod to our gameplay and style, possible changes/tweaks in:\r\n- action times\r\n- bandages efficiency\r\n- medications effects\r\n\r\n[h1]Source:[/h1]\r\nhttps://github.com/ArmaForces/Medical\r\n\r\n[h1]Other ArmaForces addons:[/h1]\r\nhttps://steamcommunity.com/sharedfiles/filedetails/?id=1643238133", + "time_created": 1580174253, + "time_updated": 1697582262, + "visibility": 0, + "banned": 0, + "ban_reason": "", + "subscriptions": 1658, + "favorited": 91, + "lifetime_subscriptions": 3969, + "lifetime_favorited": 99, + "views": 4261, + "tags": [ + { + "tag": "Mod" + }, + { + "tag": "Mechanics" + } + ] + } + ] + } +} diff --git a/src/Service/SteamApiClient/Test/data/GetPublishedFileDetails/455312245.json b/src/Service/SteamApiClient/Test/data/GetPublishedFileDetails/455312245.json new file mode 100644 index 00000000..216ec852 --- /dev/null +++ b/src/Service/SteamApiClient/Test/data/GetPublishedFileDetails/455312245.json @@ -0,0 +1,38 @@ +{ + "response": { + "result": 1, + "resultcount": 1, + "publishedfiledetails": [ + { + "publishedfileid": "455312245", + "result": 1, + "creator": "76561198198282850", + "creator_app_id": 570, + "consumer_app_id": 570, + "filename": "", + "file_size": 179337071, + "file_url": "", + "hcontent_file": "9008257739632653541", + "preview_url": "https://steamuserimages-a.akamaihd.net/ugc/261593580305582398/A96F7B8AC45675CF8C5801017225454593A198F5/", + "hcontent_preview": "261593580305582398", + "title": "Overthrow", + "description": "OBJECTIVE\nSlay your enemies! Be the first to earn the goal number of kills, or the team with the most kills when the round ends, and you will be victorious.\n\nHOW TO PLAY\n-Approach the Midas Throne to earn bonus gold and experience.\n-Snatch up any giant coins the Over Boss tosses to earn even more gold.\n-Keep an eye out for item deliveries. An icon will appear on your map where an item will appear.\n-The fewer kills your team has, the better the item you will receive from a delivery.\n-Slay anyone who isn't on your team.", + "time_created": 1433461582, + "time_updated": 1526431196, + "visibility": 0, + "banned": 0, + "ban_reason": "", + "subscriptions": 10449629, + "favorited": 780989, + "lifetime_subscriptions": 11601278, + "lifetime_favorited": 1023893, + "views": 3827854, + "tags": [ + { + "tag": "Custom Game" + } + ] + } + ] + } +} diff --git a/src/Service/SteamApiClient/Test/data/appdetails/1681170.json b/src/Service/SteamApiClient/Test/data/appdetails/1681170.json new file mode 100644 index 00000000..f93746b0 --- /dev/null +++ b/src/Service/SteamApiClient/Test/data/appdetails/1681170.json @@ -0,0 +1,321 @@ +{ + "1681170": { + "success": true, + "data": { + "type": "dlc", + "name": "Arma 3 Creator DLC: Western Sahara", + "steam_appid": 1681170, + "required_age": 0, + "is_free": false, + "detailed_description": "

ARMA 3 CREATOR DLC


Purchase this DLC to support a talented third-party developer and enjoy some of their best work yet. The Arma 3 Creator DLC program enables selected outside developers to publish original new content for Arma 3 as commercial DLC on Steam. The proceeds of Arma 3 Creator DLC: Western Sahara are shared between Rotators Collective (developer), Bohemia Interactive (publisher), and Valve (digital distributor).


About the Game

Argana, 2036. Welcome to the sprawling landscapes and punishing heat of the fictional Sefrou-Ramal province. Conflicts between rival tribes are flaring up, government forces are losing control, and an AAN war correspondent has been kidnapped. Civil war looms once again.

Become a private military contractor and be deployed to the desert dunes of Argana. This new addition to Arma 3 takes you to a hot conflict zone, brings back Arma's iconic ION PMC faction, and introduces new vehicle variants, weapons, clothing, gear, as well as singleplayer and multiplayer scenarios.

HOW TO LAUNCH


Arma 3 Creator DLC: Western Sahara is optional to install and load. To play Arma 3 with this DLC enabled, please visit the DLC section in the Arma 3 Launcher, make sure Western Sahara is owned and loaded, then launch the game by clicking the PLAY button.

DISCLAIMER

This PC game is a work of fiction. Names, characters, places and incidents are either products of the author’s imagination or are used fictitiously. The narrative is also completely fictional and does not represent or suggest any historical parallels. Any resemblance to actual events, locales or persons, living or dead, is entirely coincidental.

KEY FEATURES



Terrain: Sefrou-Ramal

Located in the northeast of Argana, the mineral rich province of Sefrou-Ramal has been a hotspot of unrest for many years due to rival tribes, underfunded peacekeeping forces, and a foreign military presence. Characterized by flowing sand dunes and desert architecture, this 100km² terrain is composed of completely new assets, as well as upgraded structures and objects from Arma 2 and Arma 3, making it as beautiful as it is mesmerizing.

5 Factions

Western Sahara features the UNA peacekeepers, the Sefrawi Freedom and Independence Army, Tura tribe insurgents, desert NATO forces, and the return of private military contractors ION Services.

To accompany these new factions, a wide number of headgear, uniform, and combat fatigue variants, as well as new civilian clothes has been added, and will allow you to blend in perfectly with the hot and dusty environment.

8 New Rifles

Repel enemy forces with the powerful Israeli IMIL GALAT automatic rifle and its modernized South African licensed variants, the Velko R4 and R5. Need fire support? The SA-77 general-purpose machine gun will help you out. Alternatively, pick up the battle-tested Belgian SLR or the modern XMS bullpup rifle, or blow your way through enemy lines with the AA40 automatic combat shotgun while your teammates lob explosive payloads via the stand-alone GLX grenade launcher system.

12 New Vehicle Variants & 1 Static Turret

New and impressive variants of existing Arma 3 vehicles make their way into Western Sahara; The Marshall lineup has been expanded with a Command Vehicle, 60mm Mortar, and an Anti-Tank Guided Missiles setup. The classic Zamak rolls through the blistering terrain in a new flatbed, cargo, and anti-air variant. The Offroad vehicle comes equipped with desert and makeshift armor kits, and the Russian PO-30 Orca helicopter has been outfitted with modern, lightweight armor plates to protect against incoming small arms fire. Additionally, new variants of the MSE-3 Marid with a .50cal manned turret and the BTR-K Kamysh featuring a hunter-killer kit have been rolled out. Last but not least, don't forget the exceptionally remastered Arma 2 asset, the ZU-23 anti-air gun.

Equipment

Western Sahara features a selection of new gear that includes a gun drone with a modular weapon attachment system, a portable ballistic shield which can be easily deployed whenever necessary, and a variety of masks like dust goggles, a military-style headset, a ballistic mask, and more.

Open-World Scenario: “Extraction”

AAN war correspondent Michael Sully has been kidnapped by insurgents and is believed to be held captive somewhere in Sefrou-Ramal. Your mission as an ION operator is to search for intel and clues and bring him back to safety. This brand new open-world scenario developed exclusively for the Western Sahara Creator DLC offers dynamically randomized contracts during the day and night and can be played in both singleplayer and multiplayer co-op with up to 4 players.

Multiplayer Mode: “King of the Dunes”

An original spin by developer Rotators Collective on the popular community-made sector control multiplayer game mode “King of the Hill” by Sa-Matra.

Multiplayer Mode and Singleplayer Showcase: "Alchemist"

A strange power of unknown origin has emerged from within the depths of the Sefrawi Desert and is calling to you! Compete against others and capture the source for yourself, or experience the Alchemist Game Mode in singleplayer against CSATs activated Viper unit.

Multiplayer Mode: “Last Stand”

Defend against waves of enemies and fight for your life against overwhelming odds in this new co-op game mode. Conserve your ammo and pick your targets carefully while working closely with a team of up to 4 people.

Showcase: “ION Weapon Systems”

Use the ION Weapon Systems VR training environment to test gear in various scenarios and prepare ION operatives for deployment.

2 Time Trial Races

Going crazy from the heat? Need to blow off some steam? Then get your motor running and race across the Sefrawi sand dunes in the Vrana-Redstone Dune Rally.

Additional Content

Rounding out Western Sahara’s immersive desert experience is a painstakingly crafted set of additional items including a digital camera, dromedary camel, refugee tents, and various new structures and props.

COMPATIBILITY DATA FOR NON-OWNERS


People who do not own the Western Sahara DLC are able to download and install the DLC's optional data via the Arma 3 Steam Workshop:

https://steamcommunity.com/sharedfiles/filedetails/?id=2636962953
Subscribing to this Workshop item makes it possible for potential buyers to try out many of the DLC's assets prior to purchasing. It also enables non-owners to join multiplayer servers that make use of DLC content. Be aware that access to the DLC's terrain and campaign remains exclusive to owners of the DLC. Restrictions to the use of non-owned content also apply.

ABOUT THE DEVELOPERS


This DLC is published by Bohemia Interactive and developed by the Rotators Collective - a small group of like-minded developers loosely assembled from all around Europe with over 10 years of experience in making mods for a wide variety of games, including the top-rated Arma 3 mini-campaigns Callsign Minotaur and Dunes. The Western Sahara DLC has been specifically designed to expand on Arma 3's 2035 near-future setting.", + "about_the_game": "Argana, 2036. Welcome to the sprawling landscapes and punishing heat of the fictional Sefrou-Ramal province. Conflicts between rival tribes are flaring up, government forces are losing control, and an AAN war correspondent has been kidnapped. Civil war looms once again.

Become a private military contractor and be deployed to the desert dunes of Argana. This new addition to Arma 3 takes you to a hot conflict zone, brings back Arma's iconic ION PMC faction, and introduces new vehicle variants, weapons, clothing, gear, as well as singleplayer and multiplayer scenarios.

HOW TO LAUNCH


Arma 3 Creator DLC: Western Sahara is optional to install and load. To play Arma 3 with this DLC enabled, please visit the DLC section in the Arma 3 Launcher, make sure Western Sahara is owned and loaded, then launch the game by clicking the PLAY button.

DISCLAIMER

This PC game is a work of fiction. Names, characters, places and incidents are either products of the author’s imagination or are used fictitiously. The narrative is also completely fictional and does not represent or suggest any historical parallels. Any resemblance to actual events, locales or persons, living or dead, is entirely coincidental.

KEY FEATURES



Terrain: Sefrou-Ramal

Located in the northeast of Argana, the mineral rich province of Sefrou-Ramal has been a hotspot of unrest for many years due to rival tribes, underfunded peacekeeping forces, and a foreign military presence. Characterized by flowing sand dunes and desert architecture, this 100km² terrain is composed of completely new assets, as well as upgraded structures and objects from Arma 2 and Arma 3, making it as beautiful as it is mesmerizing.

5 Factions

Western Sahara features the UNA peacekeepers, the Sefrawi Freedom and Independence Army, Tura tribe insurgents, desert NATO forces, and the return of private military contractors ION Services.

To accompany these new factions, a wide number of headgear, uniform, and combat fatigue variants, as well as new civilian clothes has been added, and will allow you to blend in perfectly with the hot and dusty environment.

8 New Rifles

Repel enemy forces with the powerful Israeli IMIL GALAT automatic rifle and its modernized South African licensed variants, the Velko R4 and R5. Need fire support? The SA-77 general-purpose machine gun will help you out. Alternatively, pick up the battle-tested Belgian SLR or the modern XMS bullpup rifle, or blow your way through enemy lines with the AA40 automatic combat shotgun while your teammates lob explosive payloads via the stand-alone GLX grenade launcher system.

12 New Vehicle Variants & 1 Static Turret

New and impressive variants of existing Arma 3 vehicles make their way into Western Sahara; The Marshall lineup has been expanded with a Command Vehicle, 60mm Mortar, and an Anti-Tank Guided Missiles setup. The classic Zamak rolls through the blistering terrain in a new flatbed, cargo, and anti-air variant. The Offroad vehicle comes equipped with desert and makeshift armor kits, and the Russian PO-30 Orca helicopter has been outfitted with modern, lightweight armor plates to protect against incoming small arms fire. Additionally, new variants of the MSE-3 Marid with a .50cal manned turret and the BTR-K Kamysh featuring a hunter-killer kit have been rolled out. Last but not least, don't forget the exceptionally remastered Arma 2 asset, the ZU-23 anti-air gun.

Equipment

Western Sahara features a selection of new gear that includes a gun drone with a modular weapon attachment system, a portable ballistic shield which can be easily deployed whenever necessary, and a variety of masks like dust goggles, a military-style headset, a ballistic mask, and more.

Open-World Scenario: “Extraction”

AAN war correspondent Michael Sully has been kidnapped by insurgents and is believed to be held captive somewhere in Sefrou-Ramal. Your mission as an ION operator is to search for intel and clues and bring him back to safety. This brand new open-world scenario developed exclusively for the Western Sahara Creator DLC offers dynamically randomized contracts during the day and night and can be played in both singleplayer and multiplayer co-op with up to 4 players.

Multiplayer Mode: “King of the Dunes”

An original spin by developer Rotators Collective on the popular community-made sector control multiplayer game mode “King of the Hill” by Sa-Matra.

Multiplayer Mode and Singleplayer Showcase: "Alchemist"

A strange power of unknown origin has emerged from within the depths of the Sefrawi Desert and is calling to you! Compete against others and capture the source for yourself, or experience the Alchemist Game Mode in singleplayer against CSATs activated Viper unit.

Multiplayer Mode: “Last Stand”

Defend against waves of enemies and fight for your life against overwhelming odds in this new co-op game mode. Conserve your ammo and pick your targets carefully while working closely with a team of up to 4 people.

Showcase: “ION Weapon Systems”

Use the ION Weapon Systems VR training environment to test gear in various scenarios and prepare ION operatives for deployment.

2 Time Trial Races

Going crazy from the heat? Need to blow off some steam? Then get your motor running and race across the Sefrawi sand dunes in the Vrana-Redstone Dune Rally.

Additional Content

Rounding out Western Sahara’s immersive desert experience is a painstakingly crafted set of additional items including a digital camera, dromedary camel, refugee tents, and various new structures and props.

COMPATIBILITY DATA FOR NON-OWNERS


People who do not own the Western Sahara DLC are able to download and install the DLC's optional data via the Arma 3 Steam Workshop:

https://steamcommunity.com/sharedfiles/filedetails/?id=2636962953
Subscribing to this Workshop item makes it possible for potential buyers to try out many of the DLC's assets prior to purchasing. It also enables non-owners to join multiplayer servers that make use of DLC content. Be aware that access to the DLC's terrain and campaign remains exclusive to owners of the DLC. Restrictions to the use of non-owned content also apply.

ABOUT THE DEVELOPERS


This DLC is published by Bohemia Interactive and developed by the Rotators Collective - a small group of like-minded developers loosely assembled from all around Europe with over 10 years of experience in making mods for a wide variety of games, including the top-rated Arma 3 mini-campaigns Callsign Minotaur and Dunes. The Western Sahara DLC has been specifically designed to expand on Arma 3's 2035 near-future setting.", + "short_description": "Train and operate as a military contractor, repel enemy forces with a variety of new weapons, rescue a kidnapped journalist, and race across sand dunes in the sweeping and immersive desert terrain of Sefrou-Ramal in the latest addition to Arma 3’s massive military sandbox.", + "fullgame": { + "appid": "107410", + "name": "Arma 3" + }, + "supported_languages": "English*, French, Italian, German, Spanish - Spain, Portuguese - Brazil, Russian, Simplified Chinese
*languages with full audio support", + "header_image": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/header.jpg?t=1687260861", + "capsule_image": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/capsule_231x87.jpg?t=1687260861", + "capsule_imagev5": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/capsule_184x69.jpg?t=1687260861", + "website": "http://www.arma3.com/dlc/creator", + "pc_requirements": { + "minimum": "Minimum:
  • OS: Windows 7 SP1 (64bit)
    \t
  • Processor: Intel Dual-Core 2.4 GHz or AMD Dual-Core Athlon 2.5 GHz
    \t
  • Memory: 4 GB RAM
    \t
  • Graphics: NVIDIA GeForce 9800GT / AMD Radeon HD 5670 / Intel HD Graphics 4000 with 512 MB VRAM
    \t
  • DirectX®: 10
    \t
  • Hard Drive: 50 GB free space
    \t
  • Audio: DirectX®-compatible on-board
", + "recommended": "Recommended:
  • OS: Windows 7 / 8 / 10 (64bit)
    \t
  • Processor: Intel Core i5-4460 or AMD FX 4300 or better
    \t
  • Memory: 8 GB RAM
    \t
  • Graphics: NVIDIA GeForce GTX 660 / AMD Radeon HD 7800 Series with 2 GB VRAM
    \t
  • DirectX®: 11
    \t
  • Hard Drive: 80 GB free space, SSD / Hybrid HDD / SSHD storage
    \t
  • Sound: DirectX®-compatible soundcard
" + }, + "mac_requirements": { + "minimum": "Minimum:
  • OS: macOS Big Sur 11
  • Processor: Apple M1 or 2-core Intel Core i5 1.4 GHz or better
  • Memory: 8 GB RAM
  • Graphics: Intel HD Graphics 5000 or better
  • GPU Memory: 1 GB
  • Hard Drive: 45 GB
", + "recommended": "Recommended:
  • OS: macOS Big Sur 11
  • Processor: Apple M2 or 6-core Intel Core i5 3.7 GHz or better
  • Memory: 16 GB RAM
  • Graphics: AMD Radeon Pro 580X or better
  • GPU Memory: 2 GB
  • Hard Drive: 130 GB
" + }, + "linux_requirements": [], + "legal_notice": "Arma 3 supports the BattlEye anti-cheat engine. Most server admins choose to enable it on their servers, so please refrain from cheats and hacks or you may receive a global ban. BattlEye global bans are shared with DayZ and Arma 2: Operation Arrowhead.", + "developers": [ + "Rotators Collective" + ], + "publishers": [ + "Bohemia Interactive" + ], + "price_overview": { + "currency": "PLN", + "initial": 1999, + "final": 1999, + "discount_percent": 0, + "initial_formatted": "", + "final_formatted": "19,99zł" + }, + "packages": [ + 598229 + ], + "package_groups": [ + { + "name": "default", + "title": "Buy Arma 3 Creator DLC: Western Sahara", + "description": "", + "selection_text": "Select a purchase option", + "save_text": "", + "display_type": 0, + "is_recurring_subscription": "false", + "subs": [ + { + "packageid": 598229, + "percent_savings_text": " ", + "percent_savings": 0, + "option_text": "Arma 3 Creator DLC: Western Sahara - 19,99zł", + "option_description": "", + "can_get_free_license": "0", + "is_free_license": false, + "price_in_cents_with_discount": 1999 + } + ] + } + ], + "platforms": { + "windows": true, + "mac": true, + "linux": false + }, + "categories": [ + { + "id": 2, + "description": "Single-player" + }, + { + "id": 1, + "description": "Multi-player" + }, + { + "id": 49, + "description": "PvP" + }, + { + "id": 36, + "description": "Online PvP" + }, + { + "id": 47, + "description": "LAN PvP" + }, + { + "id": 9, + "description": "Co-op" + }, + { + "id": 38, + "description": "Online Co-op" + }, + { + "id": 48, + "description": "LAN Co-op" + }, + { + "id": 21, + "description": "Downloadable Content" + }, + { + "id": 22, + "description": "Steam Achievements" + }, + { + "id": 29, + "description": "Steam Trading Cards" + }, + { + "id": 13, + "description": "Captions available" + }, + { + "id": 30, + "description": "Steam Workshop" + }, + { + "id": 18, + "description": "Partial Controller Support" + }, + { + "id": 25, + "description": "Steam Leaderboards" + }, + { + "id": 17, + "description": "Includes level editor" + } + ], + "genres": [ + { + "id": "1", + "description": "Action" + }, + { + "id": "28", + "description": "Simulation" + }, + { + "id": "2", + "description": "Strategy" + } + ], + "screenshots": [ + { + "id": 0, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_9eee558c60ea89e8df2f3d8512163726a9caf8e5.600x338.jpg?t=1687260861", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_9eee558c60ea89e8df2f3d8512163726a9caf8e5.1920x1080.jpg?t=1687260861" + }, + { + "id": 1, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_06d5a3e58a75f8c5d68b36fbc588d1e86f3f978a.600x338.jpg?t=1687260861", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_06d5a3e58a75f8c5d68b36fbc588d1e86f3f978a.1920x1080.jpg?t=1687260861" + }, + { + "id": 2, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_6ed71359a521e5a24e2e0db8a1bb7e2be8ddca77.600x338.jpg?t=1687260861", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_6ed71359a521e5a24e2e0db8a1bb7e2be8ddca77.1920x1080.jpg?t=1687260861" + }, + { + "id": 3, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_6d52c16ce1021066e3a0119f9f10ed3bffc52441.600x338.jpg?t=1687260861", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_6d52c16ce1021066e3a0119f9f10ed3bffc52441.1920x1080.jpg?t=1687260861" + }, + { + "id": 4, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_5197e8002e06171df4f5596c2acf36bd0a8ff186.600x338.jpg?t=1687260861", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_5197e8002e06171df4f5596c2acf36bd0a8ff186.1920x1080.jpg?t=1687260861" + }, + { + "id": 5, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_d5052d663df8d23010a8d86c5f6b2d90d2107f23.600x338.jpg?t=1687260861", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_d5052d663df8d23010a8d86c5f6b2d90d2107f23.1920x1080.jpg?t=1687260861" + }, + { + "id": 6, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_2b05f0e114cfb6c5ea3d9a5ed5097a03ea9c066a.600x338.jpg?t=1687260861", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_2b05f0e114cfb6c5ea3d9a5ed5097a03ea9c066a.1920x1080.jpg?t=1687260861" + }, + { + "id": 7, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_76386af026f87798a0957611d78cb62917c000ff.600x338.jpg?t=1687260861", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_76386af026f87798a0957611d78cb62917c000ff.1920x1080.jpg?t=1687260861" + }, + { + "id": 8, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_7f10c75c0012f8a7844f3159fdb90fb329a87141.600x338.jpg?t=1687260861", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_7f10c75c0012f8a7844f3159fdb90fb329a87141.1920x1080.jpg?t=1687260861" + }, + { + "id": 9, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_2a568738e0459aceb148fc06762c34d2792515d3.600x338.jpg?t=1687260861", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_2a568738e0459aceb148fc06762c34d2792515d3.1920x1080.jpg?t=1687260861" + }, + { + "id": 10, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_653ee8507c99301400b88e7383e1546b9ad61f51.600x338.jpg?t=1687260861", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_653ee8507c99301400b88e7383e1546b9ad61f51.1920x1080.jpg?t=1687260861" + }, + { + "id": 11, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_ad7a66ff437798ff07e5e940709813afd7f184fd.600x338.jpg?t=1687260861", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_ad7a66ff437798ff07e5e940709813afd7f184fd.1920x1080.jpg?t=1687260861" + }, + { + "id": 12, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_0724dc04dbbd699025a7065c7792615566b585ef.600x338.jpg?t=1687260861", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_0724dc04dbbd699025a7065c7792615566b585ef.1920x1080.jpg?t=1687260861" + }, + { + "id": 13, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_d2edf75693e9433e7cdd659a831f4e562a7a84f4.600x338.jpg?t=1687260861", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_d2edf75693e9433e7cdd659a831f4e562a7a84f4.1920x1080.jpg?t=1687260861" + }, + { + "id": 14, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_32693163ee433b1f3f6260176e75ad775f9c6e8b.600x338.jpg?t=1687260861", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_32693163ee433b1f3f6260176e75ad775f9c6e8b.1920x1080.jpg?t=1687260861" + }, + { + "id": 15, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_d3c22765cf50e2d6bed8b017fef95458410969be.600x338.jpg?t=1687260861", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_d3c22765cf50e2d6bed8b017fef95458410969be.1920x1080.jpg?t=1687260861" + }, + { + "id": 16, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_67184f06e018cb307f7f69fce4edc00315327fa6.600x338.jpg?t=1687260861", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_67184f06e018cb307f7f69fce4edc00315327fa6.1920x1080.jpg?t=1687260861" + }, + { + "id": 17, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_131dbce4fd71ee79185eb3cb3351953cb5894d15.600x338.jpg?t=1687260861", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_131dbce4fd71ee79185eb3cb3351953cb5894d15.1920x1080.jpg?t=1687260861" + }, + { + "id": 18, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_65edd20c5a48379835c8f5e35d6aea3b18f0e637.600x338.jpg?t=1687260861", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_65edd20c5a48379835c8f5e35d6aea3b18f0e637.1920x1080.jpg?t=1687260861" + }, + { + "id": 19, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_7859e4cbe326efce471b8ca23a357f57bbe99817.600x338.jpg?t=1687260861", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_7859e4cbe326efce471b8ca23a357f57bbe99817.1920x1080.jpg?t=1687260861" + }, + { + "id": 20, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_cf7e3766ee8b53cc4b419d02722d65798a0c4082.600x338.jpg?t=1687260861", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_cf7e3766ee8b53cc4b419d02722d65798a0c4082.1920x1080.jpg?t=1687260861" + }, + { + "id": 21, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_93a9092b124b1c3dcdaa57d236a9fd4a276cb11a.600x338.jpg?t=1687260861", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/ss_93a9092b124b1c3dcdaa57d236a9fd4a276cb11a.1920x1080.jpg?t=1687260861" + } + ], + "movies": [ + { + "id": 256861034, + "name": "Western Sahara Release Trailer PEGI", + "thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/256861034/movie.293x165.jpg?t=1637242240", + "webm": { + "480": "http://cdn.akamai.steamstatic.com/steam/apps/256861034/movie480_vp9.webm?t=1637242240", + "max": "http://cdn.akamai.steamstatic.com/steam/apps/256861034/movie_max_vp9.webm?t=1637242240" + }, + "mp4": { + "480": "http://cdn.akamai.steamstatic.com/steam/apps/256861034/movie480.mp4?t=1637242240", + "max": "http://cdn.akamai.steamstatic.com/steam/apps/256861034/movie_max.mp4?t=1637242240" + }, + "highlight": true + }, + { + "id": 256907865, + "name": "Western Sahara Update 1.1 Trailer PEGI", + "thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/256907865/movie.293x165.jpg?t=1664532282", + "webm": { + "480": "http://cdn.akamai.steamstatic.com/steam/apps/256907865/movie480_vp9.webm?t=1664532282", + "max": "http://cdn.akamai.steamstatic.com/steam/apps/256907865/movie_max_vp9.webm?t=1664532282" + }, + "mp4": { + "480": "http://cdn.akamai.steamstatic.com/steam/apps/256907865/movie480.mp4?t=1664532282", + "max": "http://cdn.akamai.steamstatic.com/steam/apps/256907865/movie_max.mp4?t=1664532282" + }, + "highlight": true + } + ], + "recommendations": { + "total": 802 + }, + "release_date": { + "coming_soon": false, + "date": "18 Nov, 2021" + }, + "support_info": { + "url": "http://arma3.com/faq", + "email": "support@bohemia.net" + }, + "background": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/page_bg_generated_v6b.jpg?t=1687260861", + "background_raw": "https://cdn.akamai.steamstatic.com/steam/apps/1681170/page_bg_generated.jpg?t=1687260861", + "content_descriptors": { + "ids": [ + 2, + 5 + ], + "notes": "This Game may contain content not appropriate for all ages, or may not be appropriate for viewing at work: Frequent and Intense Violence, Bad Language, General Mature Content." + } + } + } +} diff --git a/src/Service/SteamApiClient/Test/data/appdetails/2138330.json b/src/Service/SteamApiClient/Test/data/appdetails/2138330.json new file mode 100644 index 00000000..bb86a5d5 --- /dev/null +++ b/src/Service/SteamApiClient/Test/data/appdetails/2138330.json @@ -0,0 +1,270 @@ +{ + "2138330": { + "success": true, + "data": { + "type": "dlc", + "name": "Cyberpunk 2077: Phantom Liberty", + "steam_appid": 2138330, + "required_age": "18", + "is_free": false, + "detailed_description": "



", + "about_the_game": "



", + "short_description": "Phantom Liberty is a new spy-thriller expansion for the open-world action-adventure RPG Cyberpunk 2077. As cyber-enhanced mercenary V, join secret agent Solomon Reed to unravel a web of shattered loyalties and sinister political machinations.", + "fullgame": { + "appid": "1091500", + "name": "Cyberpunk 2077" + }, + "supported_languages": "English*, French*, Italian*, German*, Spanish - Spain*, Arabic, Czech, Hungarian, Japanese*, Korean*, Polish*, Portuguese - Brazil*, Russian, Simplified Chinese*, Spanish - Latin America, Thai, Traditional Chinese, Turkish, Ukrainian
*languages with full audio support", + "header_image": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/header_alt_assets_1.jpg?t=1695740414", + "capsule_image": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/capsule_231x87.jpg?t=1695740414", + "capsule_imagev5": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/capsule_184x69.jpg?t=1695740414", + "website": "https://www.cyberpunk.net", + "pc_requirements": { + "minimum": "Minimum:
  • Requires a 64-bit processor and operating system
  • OS: 64-bit Windows 10
  • Processor: Core i7-6700 or Ryzen 5 1600
  • Memory: 12 GB RAM
  • Graphics: GeForce GTX 1060 6GB or Radeon RX 580 8GB or Arc A380
  • DirectX: Version 12
  • Storage: 35 GB available space
  • Additional Notes: Attention: see upcoming change to the requirements. Storage: 35 GB SSD. In this game you will encounter a variety of visual effects that may provide seizures or loss of consciousness in a minority of people. If you or someone you know experiences any of the above symptoms while playing, stop and seek medical attention immediately.
", + "recommended": "Recommended:
  • Requires a 64-bit processor and operating system
  • OS: 64-bit Windows 10
  • Processor: Core i7-12700 or Ryzen 7 7800X3D
  • Memory: 16 GB RAM
  • Graphics: GeForce RTX 2060 SUPER or Radeon RX 5700 XT or Arc A770
  • DirectX: Version 12
  • Storage: 35 GB available space
  • Additional Notes: Storage: 35 GB SSD
" + }, + "mac_requirements": { + "minimum": "Minimum:
    ", + "recommended": "Recommended:
      " + }, + "linux_requirements": { + "minimum": "Minimum:
        ", + "recommended": "Recommended:
          " + }, + "legal_notice": "© 2023 CD PROJEKT S.A. All rights reserved. CD PROJEKT, Cyberpunk, Cyberpunk 2077, Phantom Liberty and their respective logos are registered and/or unregistered trademarks of CD PROJEKT S.A.", + "developers": [ + "CD PROJEKT RED" + ], + "publishers": [ + "CD PROJEKT RED" + ], + "price_overview": { + "currency": "EUR", + "initial": 2999, + "final": 2999, + "discount_percent": 0, + "initial_formatted": "", + "final_formatted": "29,99€" + }, + "packages": [ + 938169 + ], + "package_groups": [ + { + "name": "default", + "title": "Buy Cyberpunk 2077: Phantom Liberty", + "description": "", + "selection_text": "Select a purchase option", + "save_text": "", + "display_type": 0, + "is_recurring_subscription": "false", + "subs": [ + { + "packageid": 938169, + "percent_savings_text": " ", + "percent_savings": 0, + "option_text": "Cyberpunk 2077: Phantom Liberty - 29,99€", + "option_description": "", + "can_get_free_license": "0", + "is_free_license": false, + "price_in_cents_with_discount": 2999 + } + ] + } + ], + "platforms": { + "windows": true, + "mac": false, + "linux": false + }, + "categories": [ + { + "id": 2, + "description": "Single-player" + }, + { + "id": 21, + "description": "Downloadable Content" + }, + { + "id": 22, + "description": "Steam Achievements" + }, + { + "id": 29, + "description": "Steam Trading Cards" + }, + { + "id": 18, + "description": "Partial Controller Support" + }, + { + "id": 23, + "description": "Steam Cloud" + } + ], + "genres": [ + { + "id": "3", + "description": "RPG" + } + ], + "screenshots": [ + { + "id": 0, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_5c4b46c61d7d1d5903835a68eac6582b4e62367f.600x338.jpg?t=1695740414", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_5c4b46c61d7d1d5903835a68eac6582b4e62367f.1920x1080.jpg?t=1695740414" + }, + { + "id": 1, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_0976dd58d12a6faf07cbd2c7713a2fdb4d151896.600x338.jpg?t=1695740414", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_0976dd58d12a6faf07cbd2c7713a2fdb4d151896.1920x1080.jpg?t=1695740414" + }, + { + "id": 2, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_2d24468f7ca6dfe4cb79017db119e14f76ad9886.600x338.jpg?t=1695740414", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_2d24468f7ca6dfe4cb79017db119e14f76ad9886.1920x1080.jpg?t=1695740414" + }, + { + "id": 3, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_3ab6296c6827b4f2fd825f52be317b748ccce079.600x338.jpg?t=1695740414", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_3ab6296c6827b4f2fd825f52be317b748ccce079.1920x1080.jpg?t=1695740414" + }, + { + "id": 4, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_02c440c80edb9b5ec5008bb9031530cce79a880e.600x338.jpg?t=1695740414", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_02c440c80edb9b5ec5008bb9031530cce79a880e.1920x1080.jpg?t=1695740414" + }, + { + "id": 5, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_7bbae8adf0c05471dfea2ebb1dc2611ee0f72835.600x338.jpg?t=1695740414", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_7bbae8adf0c05471dfea2ebb1dc2611ee0f72835.1920x1080.jpg?t=1695740414" + }, + { + "id": 6, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_e6d03e7adf4c9a0dceb86eddb876da28d06f56df.600x338.jpg?t=1695740414", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_e6d03e7adf4c9a0dceb86eddb876da28d06f56df.1920x1080.jpg?t=1695740414" + }, + { + "id": 7, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_36dd158f7fb3d6a0ac30ad67dae3ce6cddfe1ac9.600x338.jpg?t=1695740414", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_36dd158f7fb3d6a0ac30ad67dae3ce6cddfe1ac9.1920x1080.jpg?t=1695740414" + }, + { + "id": 8, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_c8e6d3586c627e8502ccbcd8abcf8a6ed77657b5.600x338.jpg?t=1695740414", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_c8e6d3586c627e8502ccbcd8abcf8a6ed77657b5.1920x1080.jpg?t=1695740414" + }, + { + "id": 9, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_0e506eb18c5b9c2a6adabaa763592a91114fa3d4.600x338.jpg?t=1695740414", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_0e506eb18c5b9c2a6adabaa763592a91114fa3d4.1920x1080.jpg?t=1695740414" + }, + { + "id": 10, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_46268c01b7be460b204be19af6c2bef4e4d63e4e.600x338.jpg?t=1695740414", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_46268c01b7be460b204be19af6c2bef4e4d63e4e.1920x1080.jpg?t=1695740414" + }, + { + "id": 11, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_e64b504d41cb859ad837712a9f91ab8b82408abd.600x338.jpg?t=1695740414", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_e64b504d41cb859ad837712a9f91ab8b82408abd.1920x1080.jpg?t=1695740414" + }, + { + "id": 12, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_b47daf5e4a870a864efbf61981a698c3e9dc3f58.600x338.jpg?t=1695740414", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_b47daf5e4a870a864efbf61981a698c3e9dc3f58.1920x1080.jpg?t=1695740414" + }, + { + "id": 13, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_0458297712b24ad3b54260913b0d20df91424221.600x338.jpg?t=1695740414", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_0458297712b24ad3b54260913b0d20df91424221.1920x1080.jpg?t=1695740414" + }, + { + "id": 14, + "path_thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_a31887048b047204fceec1474e4e8699b6604bb5.600x338.jpg?t=1695740414", + "path_full": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/ss_a31887048b047204fceec1474e4e8699b6604bb5.1920x1080.jpg?t=1695740414" + } + ], + "movies": [ + { + "id": 256971774, + "name": "045_EP1_Launch_trailer_EN UK_PEGI 18_16x9_1080", + "thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/256971774/movie.293x165.jpg?t=1695740395", + "webm": { + "480": "http://cdn.akamai.steamstatic.com/steam/apps/256971774/movie480_vp9.webm?t=1695740395", + "max": "http://cdn.akamai.steamstatic.com/steam/apps/256971774/movie_max_vp9.webm?t=1695740395" + }, + "mp4": { + "480": "http://cdn.akamai.steamstatic.com/steam/apps/256971774/movie480.mp4?t=1695740395", + "max": "http://cdn.akamai.steamstatic.com/steam/apps/256971774/movie_max.mp4?t=1695740395" + }, + "highlight": true + }, + { + "id": 256969788, + "name": "105_CGI_trailer_EN UK_PEGI 18_16x9_1080", + "thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/256969788/movie.293x165.jpg?t=1695727289", + "webm": { + "480": "http://cdn.akamai.steamstatic.com/steam/apps/256969788/movie480_vp9.webm?t=1695727289", + "max": "http://cdn.akamai.steamstatic.com/steam/apps/256969788/movie_max_vp9.webm?t=1695727289" + }, + "mp4": { + "480": "http://cdn.akamai.steamstatic.com/steam/apps/256969788/movie480.mp4?t=1695727289", + "max": "http://cdn.akamai.steamstatic.com/steam/apps/256969788/movie_max.mp4?t=1695727289" + }, + "highlight": true + }, + { + "id": 256965766, + "name": "005_NWTP_trailer_EN UK_PEGI 18_16x9_1080", + "thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/256965766/movie.293x165.jpg?t=1692976089", + "webm": { + "480": "http://cdn.akamai.steamstatic.com/steam/apps/256965766/movie480_vp9.webm?t=1692976089", + "max": "http://cdn.akamai.steamstatic.com/steam/apps/256965766/movie_max_vp9.webm?t=1692976089" + }, + "mp4": { + "480": "http://cdn.akamai.steamstatic.com/steam/apps/256965766/movie480.mp4?t=1692976089", + "max": "http://cdn.akamai.steamstatic.com/steam/apps/256965766/movie_max.mp4?t=1692976089" + }, + "highlight": true + }, + { + "id": 256952346, + "name": "064_Phantom_Liberty_official_trailer_EN UK_PEGI 18_16x9_1080", + "thumbnail": "https://cdn.akamai.steamstatic.com/steam/apps/256952346/movie.293x165.jpg?t=1686664052", + "webm": { + "480": "http://cdn.akamai.steamstatic.com/steam/apps/256952346/movie480_vp9.webm?t=1686664052", + "max": "http://cdn.akamai.steamstatic.com/steam/apps/256952346/movie_max_vp9.webm?t=1686664052" + }, + "mp4": { + "480": "http://cdn.akamai.steamstatic.com/steam/apps/256952346/movie480.mp4?t=1686664052", + "max": "http://cdn.akamai.steamstatic.com/steam/apps/256952346/movie_max.mp4?t=1686664052" + }, + "highlight": true + } + ], + "recommendations": { + "total": 9993 + }, + "release_date": { + "coming_soon": false, + "date": "25 Sep, 2023" + }, + "support_info": { + "url": "http://en.cdprojektred.com/support", + "email": "" + }, + "background": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/page_bg_generated_v6b.jpg?t=1695740414", + "background_raw": "https://cdn.akamai.steamstatic.com/steam/apps/2138330/page_bg_generated.jpg?t=1695740414", + "content_descriptors": { + "ids": [ + 1, + 2, + 5 + ], + "notes": "Cyberpunk 2077 contains strong language, intense violence, blood and gore, as well as nudity and sexual material.\r\n" + } + } + } +} diff --git a/tests/integration/Service/SteamApiClient/SteamApiClientCest.php b/tests/integration/Service/SteamApiClient/SteamApiClientCest.php index 1910703d..0b0f0a7b 100644 --- a/tests/integration/Service/SteamApiClient/SteamApiClientCest.php +++ b/tests/integration/Service/SteamApiClient/SteamApiClientCest.php @@ -15,8 +15,8 @@ class SteamApiClientCest private const ITEM_NAME = 'ArmaForces - Mods'; private const ITEM_GAME_ID = 107410; - private const APP_ID = 1227700; - private const APP_NAME = 'Arma 3 Creator DLC: S.O.G. Prairie Fire'; + private const APP_ID = 1681170; + private const APP_NAME = 'Arma 3 Creator DLC: Western Sahara'; private const APP_TYPE = 'dlc'; private const APP_GAME_ID = 107410; From 6b68bce2b0bffe0ccd8efa5e16f2508d75e4fe66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Skowro=C5=84ski?= Date: Wed, 10 Jan 2024 22:50:00 +0100 Subject: [PATCH 07/17] Add home page tests --- .env.test | 4 +- tests/_support/FunctionalTester.php | 14 ++- .../Traits/CommonPageAssertsTrait.php | 105 ++++++++++++++++++ .../_support/Traits/DataTableAssertsTrait.php | 37 ++++++ tests/_support/Traits/ResponseAssertTrait.php | 73 ++++++++++++ .../_support/Traits/SecurityAssertsTrait.php | 30 +++++ tests/functional/Web/Home/IndexCest.php | 65 +++++++++++ tests/functional/Web/Home/JoinUsCest.php | 65 +++++++++++ tests/functional/Web/Home/MissionsCest.php | 59 ++++++++++ 9 files changed, 446 insertions(+), 6 deletions(-) create mode 100644 tests/_support/Traits/CommonPageAssertsTrait.php create mode 100644 tests/_support/Traits/DataTableAssertsTrait.php create mode 100644 tests/_support/Traits/ResponseAssertTrait.php create mode 100644 tests/_support/Traits/SecurityAssertsTrait.php create mode 100644 tests/functional/Web/Home/IndexCest.php create mode 100644 tests/functional/Web/Home/JoinUsCest.php create mode 100644 tests/functional/Web/Home/MissionsCest.php diff --git a/.env.test b/.env.test index 959ef8ad..09379dc7 100644 --- a/.env.test +++ b/.env.test @@ -1,7 +1,7 @@ # define your env variables for the test env here KERNEL_CLASS='App\Kernel' APP_SECRET='$ecretf0rt3st' -SYMFONY_DEPRECATIONS_HELPER=999999 +SYMFONY_DEPRECATIONS_HELPER=weak PANTHER_APP_ENV=panther PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots @@ -9,4 +9,4 @@ APP_SECURITY_OAUTH_DISCORD_SERVER_ID= APP_SECURITY_API_ALLOWED_KEYS=test_key -APP_URL_TEAMSPEAK='teamspeak.example.com' +APP_URL_TEAMSPEAK='ts3server://ts.localhost.com?password=test' diff --git a/tests/_support/FunctionalTester.php b/tests/_support/FunctionalTester.php index 7e278414..a242d049 100644 --- a/tests/_support/FunctionalTester.php +++ b/tests/_support/FunctionalTester.php @@ -4,6 +4,11 @@ namespace App\Tests; +use App\Test\Traits\TimeTrait; +use App\Tests\Traits\CommonPageAssertsTrait; +use App\Tests\Traits\DataTableAssertsTrait; +use App\Tests\Traits\ResponseAssertTrait; +use App\Tests\Traits\SecurityAssertsTrait; use Codeception\Actor; use Codeception\Lib\Friend; @@ -25,8 +30,9 @@ class FunctionalTester extends Actor { use _generated\FunctionalTesterActions; - - /** - * Define custom actions here. - */ + use CommonPageAssertsTrait; + use DataTableAssertsTrait; + use ResponseAssertTrait; + use SecurityAssertsTrait; + use TimeTrait; } diff --git a/tests/_support/Traits/CommonPageAssertsTrait.php b/tests/_support/Traits/CommonPageAssertsTrait.php new file mode 100644 index 00000000..4b51fa93 --- /dev/null +++ b/tests/_support/Traits/CommonPageAssertsTrait.php @@ -0,0 +1,105 @@ +seeCommonNavbarElements(); + + $this->dontSeeLink('Manage mods'); + $this->dontSeeLink('Mods'); + $this->dontSeeLink('Mod groups'); + $this->dontSeeLink('DLCs'); + $this->dontSeeLink('Mod lists'); + + $this->dontSeeLink('Manage users'); + $this->dontSeeLink('Users'); + $this->dontSeeLink('User groups'); + + $this->dontSeeElement('a[href="ts3server://ts.localhost.com?password=test"]'); + + $this->seeLink('Login'); + $this->dontSeeLink('Logout'); + } + + public function seePageNavbarAsAuthenticatedUser(): void + { + $this->seeCommonNavbarElements(); + + $this->dontSeeLink('Manage mods'); + $this->dontSeeLink('Mods'); + $this->dontSeeLink('Mod groups'); + $this->dontSeeLink('DLCs'); + $this->dontSeeLink('Mod lists'); + + $this->dontSeeLink('Manage users'); + $this->dontSeeLink('Users'); + $this->dontSeeLink('User groups'); + + $this->seeElement('a[href="ts3server://ts.localhost.com?password=test"]'); + + $this->dontSeeLink('Login'); + $this->seeLink('Logout'); + } + + public function seePageNavbarAsAdmin(): void + { + $this->seeCommonNavbarElements(); + + $this->seeLink('Manage mods'); + $this->seeLink('Mods'); + $this->seeLink('Mod groups'); + $this->seeLink('DLCs'); + $this->seeLink('Mod lists'); + + $this->seeElement('a[href="ts3server://ts.localhost.com?password=test"]'); + + $this->seeLink('Manage users'); + $this->seeLink('Users'); + $this->seeLink('User groups'); + } + + public function seeActionButton(string $tooltip, string $url = null): void + { + $selector = sprintf('a i[title="%s"]', $tooltip); + if ($url) { + $selector = sprintf('a[href="%s"] i[title="%s"]', $url, $tooltip); + } + $this->seeElement($selector); + } + + public function dontSeeActionButton(string $tooltip, string $url = null): void + { + $selector = sprintf('a i[title="%s"]', $tooltip); + if ($url) { + $selector = sprintf('a[href="%s"] i[title="%s"]', $url, $tooltip); + } + $this->dontSeeElement($selector); + } + + public function seePageFooter(): void + { + $this->seeLink('Statute', 'https://drive.google.com/file/d/1a2Ote4EegVOxYUP7Un9gosLzBSmWV8fj'); + $this->seeLink('Calendar', 'https://docs.google.com/spreadsheets/d/1t1158AsoxIwXI5FlPNjqbaXk6Cx7oq7Ocgchnsk2_TE'); + $this->seeLink('Wiki', 'https://wiki.armaforces.com'); + } + + private function seeCommonNavbarElements(): void + { + $this->seeLink('Homepage'); + $this->seeLink('Missions'); + $this->seeLink('Get mods'); + + $this->seeElement('a[href="https://github.com/ArmaForces"]'); + $this->seeElement('a[href="https://discord.gg/wcuVSrU"]'); + $this->seeElement('a[href="https://steamcommunity.com/id/armaforces/myworkshopfiles?appid=107410"]'); + + $this->seeLink('Statute', 'https://drive.google.com/file/d/1a2Ote4EegVOxYUP7Un9gosLzBSmWV8fj'); + $this->seeLink('Calendar', 'https://docs.google.com/spreadsheets/d/1t1158AsoxIwXI5FlPNjqbaXk6Cx7oq7Ocgchnsk2_TE'); + $this->seeLink('Wiki', 'https://wiki.armaforces.com'); + } +} diff --git a/tests/_support/Traits/DataTableAssertsTrait.php b/tests/_support/Traits/DataTableAssertsTrait.php new file mode 100644 index 00000000..c0acccc1 --- /dev/null +++ b/tests/_support/Traits/DataTableAssertsTrait.php @@ -0,0 +1,37 @@ +checkOption(sprintf('[value="%s"]', $value)); + } + + public function uncheckTableRowCheckbox(string $value): void + { + $this->uncheckOption(sprintf('[value="%s"]', $value)); + } + + public function seeTableRowCheckboxesAreChecked(array $values = []): void + { + $valueSelector = array_map(fn (string $value) => sprintf('[value="%s"]', $value), $values); + $checkboxSelector = implode(', ', $valueSelector); + + $this->seeCheckboxIsChecked($checkboxSelector); + } + + public function seeTableRowCheckboxesAreUnchecked(string $idPrefix, array $valuesToExclude = []): void + { + $checkboxSelector = sprintf('[id^="%s"]', $idPrefix); + if ($valuesToExclude) { + $valueSelector = array_map(fn (string $value) => sprintf(':not([value^="%s"])', $value), $valuesToExclude); + $checkboxSelector .= implode('', $valueSelector); + } + + $this->dontSeeCheckboxIsChecked($checkboxSelector); + } +} diff --git a/tests/_support/Traits/ResponseAssertTrait.php b/tests/_support/Traits/ResponseAssertTrait.php new file mode 100644 index 00000000..c52748d3 --- /dev/null +++ b/tests/_support/Traits/ResponseAssertTrait.php @@ -0,0 +1,73 @@ +seeResponseCodeIsRedirection(); + $this->seeHttpHeader('Location', $url); + } + + public function seeResponseRedirectsToLogInAction(): void + { + $this->seeResponseRedirectsTo('/security/connect/discord'); + } + + public function seeResponseRedirectsToDiscordOauth(): void + { + $this->seeResponseCodeIsRedirection(); + $redirect = $this->grabHttpHeader('Location'); + $this->assertTrue(str_starts_with($redirect, 'https://discord.com/oauth2/authorize')); + } + + public function seeResponseContainsModListPresetWithMods( + string $fileName, + array $expectedDlcs, + array $expectedMods, + ): void { + $extractSteamWorkshopItems = function (Crawler $crawler, string $containerName) { + $containerSelector = sprintf('[data-type="%s"]', $containerName); + $containerCrawler = $crawler->filter($containerSelector); + + return array_map(static function (\DOMNode $steamWorkshopItemNode) { + $steamWorkshopItemNodeCrawler = (new Crawler($steamWorkshopItemNode)); + + return [ + 'name' => $steamWorkshopItemNodeCrawler->filter('[data-type="DisplayName"]')->html(), + 'url' => $steamWorkshopItemNodeCrawler->filter('[data-type="Link"]')->attr('href'), + ]; + }, iterator_to_array($containerCrawler->getIterator())); + }; + + $this->seeHttpHeader('Content-Disposition', sprintf('attachment; filename="%s"', $fileName)); + + $crawler = new Crawler($this->grabResponse()); + $includedDlcs = $extractSteamWorkshopItems($crawler, 'DlcContainer'); + $includedMods = $extractSteamWorkshopItems($crawler, 'ModContainer'); + + $expectedDlcs = array_map(static function (Dlc $dlc) { + return [ + 'name' => $dlc->getName(), + 'url' => "https://store.steampowered.com/app/{$dlc->getAppId()}", + ]; + }, $expectedDlcs); + + $expectedMods = array_map(static function (SteamWorkshopMod $steamWorkshopMod) { + return [ + 'name' => $steamWorkshopMod->getName(), + 'url' => "https://steamcommunity.com/sharedfiles/filedetails/?id={$steamWorkshopMod->getItemId()}", + ]; + }, $expectedMods); + + $this->assertSame($expectedDlcs, $includedDlcs); + $this->assertSame($expectedMods, $includedMods); + } +} diff --git a/tests/_support/Traits/SecurityAssertsTrait.php b/tests/_support/Traits/SecurityAssertsTrait.php new file mode 100644 index 00000000..42ab4866 --- /dev/null +++ b/tests/_support/Traits/SecurityAssertsTrait.php @@ -0,0 +1,30 @@ +grabEntityFromRepository(User::class, ['id' => $id]); + if ($preAuthCallback) { + $preAuthCallback($user); + + // Refresh user entity to avoid permission issues in subsequent requests + $this->haveInRepository($user); + } + $this->amLoggedInAs($user); + + return $user; + } + + public function amApiKeyAuthenticatedAs(string $apiKey, string $headerName = 'X-API-KEY'): void + { + $this->haveHttpHeader($headerName, $apiKey); + } +} diff --git a/tests/functional/Web/Home/IndexCest.php b/tests/functional/Web/Home/IndexCest.php new file mode 100644 index 00000000..7f785daf --- /dev/null +++ b/tests/functional/Web/Home/IndexCest.php @@ -0,0 +1,65 @@ +amOnPage('/'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seePageNavbarAsUnauthenticatedUser(); + + $I->seeLink('About us'); + $I->seeLink('Join us!'); + + $I->seeElement('a[href="https://docs.google.com/spreadsheets/d/1t1158AsoxIwXI5FlPNjqbaXk6Cx7oq7Ocgchnsk2_TE"]'); + + $I->seePageFooter(); + } + + public function visitHomePageAsAuthenticatedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage('/'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seePageNavbarAsAuthenticatedUser(); + + $I->seeLink('About us'); + $I->seeLink('Join us!'); + + $I->seeElement('a[href="https://docs.google.com/spreadsheets/d/1t1158AsoxIwXI5FlPNjqbaXk6Cx7oq7Ocgchnsk2_TE"]'); + + $I->seePageFooter(); + } + + public function visitHomePageAsAuthenticatedUserWithFullPermissions(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(AdminFixture::ID); + + $I->amOnPage('/'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seePageNavbarAsAdmin(); + + $I->seeLink('About us'); + $I->seeLink('Join us!'); + + $I->seeElement('a[href="https://docs.google.com/spreadsheets/d/1t1158AsoxIwXI5FlPNjqbaXk6Cx7oq7Ocgchnsk2_TE"]'); + + $I->seePageFooter(); + } +} diff --git a/tests/functional/Web/Home/JoinUsCest.php b/tests/functional/Web/Home/JoinUsCest.php new file mode 100644 index 00000000..30e0c9e6 --- /dev/null +++ b/tests/functional/Web/Home/JoinUsCest.php @@ -0,0 +1,65 @@ +amOnPage('/join-us'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seePageNavbarAsUnauthenticatedUser(); + + $I->seeElement('a[href="https://drive.google.com/file/d/1a2Ote4EegVOxYUP7Un9gosLzBSmWV8fj"]'); + $I->seeElement('a[href="https://discord.gg/wcuVSrU"]'); + $I->seeElement('a[href="#"]'); + $I->seeElement('a[href="/mod-list/Default"]'); + + $I->seePageFooter(); + } + + public function visitJoinUsPageAsAuthenticatedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage('/join-us'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seePageNavbarAsAuthenticatedUser(); + + $I->seeElement('a[href="https://drive.google.com/file/d/1a2Ote4EegVOxYUP7Un9gosLzBSmWV8fj"]'); + $I->seeElement('a[href="https://discord.gg/wcuVSrU"]'); + $I->seeElement('a[href="ts3server://ts.localhost.com?password=test"]'); + $I->seeElement('a[href="/mod-list/Default"]'); + + $I->seePageFooter(); + } + + public function visitJoinUsPageAsAuthenticatedUserWithFullPermissions(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(AdminFixture::ID); + + $I->amOnPage('/join-us'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seePageNavbarAsAdmin(); + + $I->seeElement('a[href="https://drive.google.com/file/d/1a2Ote4EegVOxYUP7Un9gosLzBSmWV8fj"]'); + $I->seeElement('a[href="https://discord.gg/wcuVSrU"]'); + $I->seeElement('a[href="ts3server://ts.localhost.com?password=test"]'); + $I->seeElement('a[href="/mod-list/Default"]'); + + $I->seePageFooter(); + } +} diff --git a/tests/functional/Web/Home/MissionsCest.php b/tests/functional/Web/Home/MissionsCest.php new file mode 100644 index 00000000..68d9dafb --- /dev/null +++ b/tests/functional/Web/Home/MissionsCest.php @@ -0,0 +1,59 @@ +amOnPage('/missions'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seePageNavbarAsUnauthenticatedUser(); + + $I->see('Upcoming missions'); + $I->see('Completed missions'); + + $I->seePageFooter(); + } + + public function visitMissionsPageAsAuthenticatedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage('/missions'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seePageNavbarAsAuthenticatedUser(); + + $I->see('Upcoming missions'); + $I->see('Completed missions'); + + $I->seePageFooter(); + } + + public function visitMissionsPageAsAuthenticatedUserWithFullPermissions(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(AdminFixture::ID); + + $I->amOnPage('/missions'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seePageNavbarAsAdmin(); + + $I->see('Upcoming missions'); + $I->see('Completed missions'); + + $I->seePageFooter(); + } +} From babdda89cfc4cb031a59a446ca0a381723c7dac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Skowro=C5=84ski?= Date: Wed, 10 Jan 2024 22:52:19 +0100 Subject: [PATCH 08/17] Add security tests --- tests/functional/Web/Security/ConnectCest.php | 32 +++++++++++++++++++ tests/functional/Web/Security/LogoutCest.php | 32 +++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 tests/functional/Web/Security/ConnectCest.php create mode 100644 tests/functional/Web/Security/LogoutCest.php diff --git a/tests/functional/Web/Security/ConnectCest.php b/tests/functional/Web/Security/ConnectCest.php new file mode 100644 index 00000000..afdb17af --- /dev/null +++ b/tests/functional/Web/Security/ConnectCest.php @@ -0,0 +1,32 @@ +stopFollowingRedirects(); + } + + public function logInAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage('/security/connect/discord'); + + $I->seeResponseRedirectsToDiscordOauth(); + } + + public function logInAsRegisteredUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage('/security/connect/discord'); + + $I->seeResponseRedirectsTo('/'); + } +} diff --git a/tests/functional/Web/Security/LogoutCest.php b/tests/functional/Web/Security/LogoutCest.php new file mode 100644 index 00000000..1ab5dc96 --- /dev/null +++ b/tests/functional/Web/Security/LogoutCest.php @@ -0,0 +1,32 @@ +stopFollowingRedirects(); + } + + public function logOutAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage('/security/logout'); + $I->seeResponseRedirectsTo('http://localhost/'); + } + + public function logOutAsRegisteredUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage('/security/logout'); + $I->seeResponseRedirectsTo('http://localhost/'); + + $I->dontSeeAuthentication(); + } +} From 25f3bb3797b3f3d16e2722c0d47969f2546985a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Skowro=C5=84ski?= Date: Wed, 10 Jan 2024 22:52:24 +0100 Subject: [PATCH 09/17] Add user tests --- config/services.yaml | 7 + src/Form/User/UserFormType.php | 4 +- tests/functional/Web/User/DeleteUserCest.php | 76 ++++ tests/functional/Web/User/ListUsersCest.php | 79 +++++ tests/functional/Web/User/UpdateUserCest.php | 343 +++++++++++++++++++ 5 files changed, 507 insertions(+), 2 deletions(-) create mode 100644 tests/functional/Web/User/DeleteUserCest.php create mode 100644 tests/functional/Web/User/ListUsersCest.php create mode 100644 tests/functional/Web/User/UpdateUserCest.php diff --git a/config/services.yaml b/config/services.yaml index 15af80a2..da581f1c 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -114,3 +114,10 @@ services: App\Form\DataTransformerRegistry: arguments: $registeredDataTransformers: !tagged_iterator app.form.registered_data_transformer + +when@test: + services: + security.helper: # see: https://github.com/Codeception/module-symfony/issues/34 + class: Symfony\Bundle\SecurityBundle\Security + arguments: + - '@test.service_container' diff --git a/src/Form/User/UserFormType.php b/src/Form/User/UserFormType.php index b737b0c1..2cf424f7 100644 --- a/src/Form/User/UserFormType.php +++ b/src/Form/User/UserFormType.php @@ -8,7 +8,7 @@ use App\Form\Permissions\PermissionsType; use App\Form\User\Dto\UserFormDto; use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\Extension\Core\Type\NumberType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -17,7 +17,7 @@ class UserFormType extends AbstractType public function buildForm(FormBuilderInterface $builder, array $options): void { $builder - ->add('steamId', TextType::class, [ + ->add('steamId', NumberType::class, [ 'label' => 'Steam ID', ]) ->add('permissions', PermissionsType::class, [ diff --git a/tests/functional/Web/User/DeleteUserCest.php b/tests/functional/Web/User/DeleteUserCest.php new file mode 100644 index 00000000..f47f4e82 --- /dev/null +++ b/tests/functional/Web/User/DeleteUserCest.php @@ -0,0 +1,76 @@ +stopFollowingRedirects(); + } + + public function deleteUserAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage(sprintf('/user/%s/delete', User2Fixture::ID)); + + $I->seeResponseRedirectsToLogInAction(); + + $I->seeInRepository(User::class, ['id' => User2Fixture::ID]); + } + + public function deleteUserAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage(sprintf('/user/%s/delete', User2Fixture::ID)); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + + $I->seeInRepository(User::class, ['id' => User2Fixture::ID]); + } + + public function deleteUserAsAuthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userDelete = true; + }); + + $I->amOnPage(sprintf('/user/%s/delete', User2Fixture::ID)); + + $I->seeResponseRedirectsTo('/user/list'); + + $I->dontSeeInRepository(User::class, ['id' => User2Fixture::ID]); + } + + public function deleteSelfAsAuthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userDelete = true; + }); + + $I->amOnPage(sprintf('/user/%s/delete', User1Fixture::ID)); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + + $I->seeInRepository(User::class, ['id' => User1Fixture::ID]); + } + + public function deleteUserAsAuthorizedUserWhenUserDoesNotExist(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userDelete = true; + }); + + $I->amOnPage(sprintf('/user/%s/delete', 'd2cca3c6-1c5f-4ea7-afcf-a05317a58467')); + + $I->seeResponseCodeIs(HttpCode::NOT_FOUND); + } +} diff --git a/tests/functional/Web/User/ListUsersCest.php b/tests/functional/Web/User/ListUsersCest.php new file mode 100644 index 00000000..fdff9459 --- /dev/null +++ b/tests/functional/Web/User/ListUsersCest.php @@ -0,0 +1,79 @@ +stopFollowingRedirects(); + } + + public function listUsersAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage('/user/list'); + + $I->seeResponseRedirectsToLogInAction(); + } + + public function listUsersAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage('/user/list'); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + } + + public function listUsersAsAuthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userList = true; + }); + + $I->amOnPage('/user/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->dontSeeActionButton('Edit user'); + $I->dontSeeActionButton('Delete user'); + } + + public function listUsersAsAuthorizedUserWithUpdateUserPermission(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userList = true; + $user->getPermissions()->userUpdate = true; + }); + + $I->amOnPage('/user/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeActionButton('Edit user'); + $I->dontSeeActionButton('Delete user'); + } + + public function listUsersAsAuthorizedUserWithDeleteUserPermission(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userList = true; + $user->getPermissions()->userDelete = true; + }); + + $I->amOnPage('/user/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->dontSeeActionButton('Edit user'); + $I->seeActionButton('Delete user'); + $I->dontSeeActionButton('Delete user', sprintf('/user/%s/delete', User1Fixture::ID)); + } +} diff --git a/tests/functional/Web/User/UpdateUserCest.php b/tests/functional/Web/User/UpdateUserCest.php new file mode 100644 index 00000000..68fcc8ed --- /dev/null +++ b/tests/functional/Web/User/UpdateUserCest.php @@ -0,0 +1,343 @@ +stopFollowingRedirects(); + $I->freezeTime('2021-01-01T00:00:00+00:00'); + } + + public function updateUserAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage(sprintf('/user/%s/update', User2Fixture::ID)); + + $I->seeResponseRedirectsToLogInAction(); + } + + public function updateUserAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage(sprintf('/user/%s/update', User2Fixture::ID)); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + } + + public function updateUserAsAuthorizedUser(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userUpdate = true; + }); + + $I->amOnPage(sprintf('/user/%s/update', User2Fixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeInField('Steam ID', User2Fixture::STEAM_ID); + + $I->dontSeeCheckboxIsChecked('Can list users'); + $I->dontSeeCheckboxIsChecked('Can edit users'); + $I->dontSeeCheckboxIsChecked('Can delete users'); + + $I->dontSeeCheckboxIsChecked('Can list user groups'); + $I->dontSeeCheckboxIsChecked('Can create user groups'); + $I->dontSeeCheckboxIsChecked('Can edit user groups'); + $I->dontSeeCheckboxIsChecked('Can delete user groups'); + + $I->dontSeeCheckboxIsChecked('Can list mods'); + $I->dontSeeCheckboxIsChecked('Can create mods'); + $I->dontSeeCheckboxIsChecked('Can edit mods'); + $I->dontSeeCheckboxIsChecked('Can delete mods'); + $I->dontSeeCheckboxIsChecked('Can change mods status'); + + $I->dontSeeCheckboxIsChecked('Can list mod groups'); + $I->dontSeeCheckboxIsChecked('Can create mod groups'); + $I->dontSeeCheckboxIsChecked('Can edit mod groups'); + $I->dontSeeCheckboxIsChecked('Can delete mod groups'); + + $I->dontSeeCheckboxIsChecked('Can list DLCs'); + $I->dontSeeCheckboxIsChecked('Can create DLCs'); + $I->dontSeeCheckboxIsChecked('Can edit DLCs'); + $I->dontSeeCheckboxIsChecked('Can delete DLCs'); + + $I->dontSeeCheckboxIsChecked('Can list mod lists'); + $I->dontSeeCheckboxIsChecked('Can create mod lists'); + $I->dontSeeCheckboxIsChecked('Can edit other users mod lists'); + $I->dontSeeCheckboxIsChecked('Can copy mod lists'); + $I->dontSeeCheckboxIsChecked('Can delete other users mod lists'); + $I->dontSeeCheckboxIsChecked('Can approve mod lists'); + + // Fill form + $I->fillField('Steam ID', 12345678901234567); + + $I->checkOption('Can list users'); + $I->checkOption('Can edit users'); + $I->checkOption('Can delete users'); + + $I->checkOption('Can list user groups'); + $I->checkOption('Can create user groups'); + $I->checkOption('Can edit user groups'); + $I->checkOption('Can delete user groups'); + + $I->checkOption('Can list mods'); + $I->checkOption('Can create mods'); + $I->checkOption('Can edit mods'); + $I->checkOption('Can delete mods'); + $I->checkOption('Can change mods status'); + + $I->checkOption('Can list mod groups'); + $I->checkOption('Can create mod groups'); + $I->checkOption('Can edit mod groups'); + $I->checkOption('Can delete mod groups'); + + $I->checkOption('Can list DLCs'); + $I->checkOption('Can create DLCs'); + $I->checkOption('Can edit DLCs'); + $I->checkOption('Can delete DLCs'); + + $I->checkOption('Can list mod lists'); + $I->checkOption('Can create mod lists'); + $I->checkOption('Can edit other users mod lists'); + $I->checkOption('Can copy mod lists'); + $I->checkOption('Can delete other users mod lists'); + $I->checkOption('Can approve mod lists'); + $I->click('Apply'); + + $I->seeResponseRedirectsTo('/user/list'); + + /** @var User $user */ + $user = $I->grabEntityFromRepository(User::class, ['id' => User2Fixture::ID]); + $I->assertSame(12345678901234567, $user->getSteamId()); + + $I->assertTrue($user->getPermissions()->userList); + $I->assertTrue($user->getPermissions()->userUpdate); + $I->assertTrue($user->getPermissions()->userDelete); + + $I->assertTrue($user->getPermissions()->userGroupList); + $I->assertTrue($user->getPermissions()->userGroupCreate); + $I->assertTrue($user->getPermissions()->userGroupUpdate); + $I->assertTrue($user->getPermissions()->userGroupDelete); + + $I->assertTrue($user->getPermissions()->modList); + $I->assertTrue($user->getPermissions()->modCreate); + $I->assertTrue($user->getPermissions()->modUpdate); + $I->assertTrue($user->getPermissions()->modDelete); + $I->assertTrue($user->getPermissions()->modChangeStatus); + + $I->assertTrue($user->getPermissions()->modGroupList); + $I->assertTrue($user->getPermissions()->modGroupCreate); + $I->assertTrue($user->getPermissions()->modGroupUpdate); + $I->assertTrue($user->getPermissions()->modGroupDelete); + + $I->assertTrue($user->getPermissions()->dlcList); + $I->assertTrue($user->getPermissions()->dlcCreate); + $I->assertTrue($user->getPermissions()->dlcUpdate); + $I->assertTrue($user->getPermissions()->dlcDelete); + + $I->assertTrue($user->getPermissions()->modListList); + $I->assertTrue($user->getPermissions()->modListCreate); + $I->assertTrue($user->getPermissions()->modListUpdate); + $I->assertTrue($user->getPermissions()->modListCopy); + $I->assertTrue($user->getPermissions()->modListDelete); + $I->assertTrue($user->getPermissions()->modListApprove); + + $I->assertSame('2020-01-01T00:00:00+00:00', $user->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame(null, $user->getCreatedBy()?->getId()->toString()); + $I->assertSame('2021-01-01T00:00:00+00:00', $user->getLastUpdatedAt()?->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $user->getLastUpdatedBy()?->getId()->toString()); + } + + public function updateSelfAsAuthorizedUser(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userList = true; + $user->getPermissions()->userUpdate = true; + }); + + $I->amOnPage(sprintf('/user/%s/update', User1Fixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeInField('Steam ID', User1Fixture::STEAM_ID); + + $I->seeElement('#user_form_permissions_userList[disabled][checked]'); + $I->seeElement('#user_form_permissions_userUpdate[disabled][checked]'); + $I->dontSeeCheckboxIsChecked('Can delete users'); + + $I->dontSeeCheckboxIsChecked('Can list user groups'); + $I->dontSeeCheckboxIsChecked('Can create user groups'); + $I->dontSeeCheckboxIsChecked('Can edit user groups'); + $I->dontSeeCheckboxIsChecked('Can delete user groups'); + + $I->dontSeeCheckboxIsChecked('Can list mods'); + $I->dontSeeCheckboxIsChecked('Can create mods'); + $I->dontSeeCheckboxIsChecked('Can edit mods'); + $I->dontSeeCheckboxIsChecked('Can delete mods'); + $I->dontSeeCheckboxIsChecked('Can change mods status'); + + $I->dontSeeCheckboxIsChecked('Can list mod groups'); + $I->dontSeeCheckboxIsChecked('Can create mod groups'); + $I->dontSeeCheckboxIsChecked('Can edit mod groups'); + $I->dontSeeCheckboxIsChecked('Can delete mod groups'); + + $I->dontSeeCheckboxIsChecked('Can list DLCs'); + $I->dontSeeCheckboxIsChecked('Can create DLCs'); + $I->dontSeeCheckboxIsChecked('Can edit DLCs'); + $I->dontSeeCheckboxIsChecked('Can delete DLCs'); + + $I->dontSeeCheckboxIsChecked('Can list mod lists'); + $I->dontSeeCheckboxIsChecked('Can create mod lists'); + $I->dontSeeCheckboxIsChecked('Can edit other users mod lists'); + $I->dontSeeCheckboxIsChecked('Can copy mod lists'); + $I->dontSeeCheckboxIsChecked('Can delete other users mod lists'); + $I->dontSeeCheckboxIsChecked('Can approve mod lists'); + + // Fill form + $I->fillField('Steam ID', 12345678901234567); + + $I->checkOption('Can delete users'); + + $I->checkOption('Can list user groups'); + $I->checkOption('Can create user groups'); + $I->checkOption('Can edit user groups'); + $I->checkOption('Can delete user groups'); + + $I->checkOption('Can list mods'); + $I->checkOption('Can create mods'); + $I->checkOption('Can edit mods'); + $I->checkOption('Can delete mods'); + $I->checkOption('Can change mods status'); + + $I->checkOption('Can list mod groups'); + $I->checkOption('Can create mod groups'); + $I->checkOption('Can edit mod groups'); + $I->checkOption('Can delete mod groups'); + + $I->checkOption('Can list DLCs'); + $I->checkOption('Can create DLCs'); + $I->checkOption('Can edit DLCs'); + $I->checkOption('Can delete DLCs'); + + $I->checkOption('Can list mod lists'); + $I->checkOption('Can create mod lists'); + $I->checkOption('Can edit other users mod lists'); + $I->checkOption('Can copy mod lists'); + $I->checkOption('Can delete other users mod lists'); + $I->checkOption('Can approve mod lists'); + $I->click('Apply'); + + $I->seeResponseRedirectsTo('/user/list'); + + /** @var User $user */ + $user = $I->grabEntityFromRepository(User::class, ['id' => User1Fixture::ID]); + $I->assertSame(12345678901234567, $user->getSteamId()); + + $I->assertTrue($user->getPermissions()->userDelete); + + $I->assertTrue($user->getPermissions()->userGroupList); + $I->assertTrue($user->getPermissions()->userGroupCreate); + $I->assertTrue($user->getPermissions()->userGroupUpdate); + $I->assertTrue($user->getPermissions()->userGroupDelete); + + $I->assertTrue($user->getPermissions()->modList); + $I->assertTrue($user->getPermissions()->modCreate); + $I->assertTrue($user->getPermissions()->modUpdate); + $I->assertTrue($user->getPermissions()->modDelete); + $I->assertTrue($user->getPermissions()->modChangeStatus); + + $I->assertTrue($user->getPermissions()->modGroupList); + $I->assertTrue($user->getPermissions()->modGroupCreate); + $I->assertTrue($user->getPermissions()->modGroupUpdate); + $I->assertTrue($user->getPermissions()->modGroupDelete); + + $I->assertTrue($user->getPermissions()->dlcList); + $I->assertTrue($user->getPermissions()->dlcCreate); + $I->assertTrue($user->getPermissions()->dlcUpdate); + $I->assertTrue($user->getPermissions()->dlcDelete); + + $I->assertTrue($user->getPermissions()->modListList); + $I->assertTrue($user->getPermissions()->modListCreate); + $I->assertTrue($user->getPermissions()->modListUpdate); + $I->assertTrue($user->getPermissions()->modListCopy); + $I->assertTrue($user->getPermissions()->modListDelete); + $I->assertTrue($user->getPermissions()->modListApprove); + + $I->assertSame('2020-01-01T00:00:00+00:00', $user->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame(null, $user->getCreatedBy()?->getId()->toString()); + $I->assertSame('2021-01-01T00:00:00+00:00', $user->getLastUpdatedAt()?->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $user->getLastUpdatedBy()?->getId()->toString()); + } + + public function updateUserAsAuthorizedUserWhenUserAlreadyExists(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userUpdate = true; + }); + + $I->amOnPage(sprintf('/user/%s/update', User2Fixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Steam ID', User3Fixture::STEAM_ID); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('steamId', 'User with the same Steam ID "33333333333333333" already exist.'); + } + + #[DataProvider('invalidSteamIdDataProvider')] + public function updateUserAsAuthorizedUserWithInvalidSteamId(FunctionalTester $I, Example $example): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userUpdate = true; + }); + + $I->amOnPage(sprintf('/user/%s/update', User2Fixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Steam ID', $example['steamId']); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('steamId', $example['error']); + } + + public function updateUserAsAuthorizedUserWhenUserDoesNotExist(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userUpdate = true; + }); + + $I->amOnPage(sprintf('/user/%s/update', 'd2cca3c6-1c5f-4ea7-afcf-a05317a58467')); + + $I->seeResponseCodeIs(HttpCode::NOT_FOUND); + } + + protected function invalidSteamIdDataProvider(): array + { + return [ + ['steamId' => 'asd', 'error' => 'Please enter a number.'], + ['steamId' => '123', 'error' => 'Invalid Steam profile ID.'], + ['steamId' => '1234567890123456789', 'error' => 'Invalid Steam profile ID.'], + ]; + } +} From 35c1f502a31b91fad26bb1a9d812f89e153752a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Skowro=C5=84ski?= Date: Wed, 10 Jan 2024 22:52:31 +0100 Subject: [PATCH 10/17] Add user group tests --- .../Web/UserGroup/CreateUserGroupCest.php | 206 ++++++++++++++++++ .../Web/UserGroup/DeleteUserGroupCest.php | 64 ++++++ .../Web/UserGroup/ListUserGroupsCest.php | 97 +++++++++ .../Web/UserGroup/UpdateUserGroupCest.php | 191 ++++++++++++++++ 4 files changed, 558 insertions(+) create mode 100644 tests/functional/Web/UserGroup/CreateUserGroupCest.php create mode 100644 tests/functional/Web/UserGroup/DeleteUserGroupCest.php create mode 100644 tests/functional/Web/UserGroup/ListUserGroupsCest.php create mode 100644 tests/functional/Web/UserGroup/UpdateUserGroupCest.php diff --git a/tests/functional/Web/UserGroup/CreateUserGroupCest.php b/tests/functional/Web/UserGroup/CreateUserGroupCest.php new file mode 100644 index 00000000..304d17b8 --- /dev/null +++ b/tests/functional/Web/UserGroup/CreateUserGroupCest.php @@ -0,0 +1,206 @@ +stopFollowingRedirects(); + + $I->freezeTime('2020-01-01T00:00:00+00:00'); + } + + public function createUserGroupAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage('/user-group/create'); + + $I->seeResponseRedirectsToLogInAction(); + } + + public function createUserGroupAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage('/user-group/create'); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + } + + public function createUserGroupAsAuthorizedUser(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userGroupCreate = true; + }); + + $I->amOnPage('/user-group/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeInField('User group name', ''); + $I->seeInField('User group description', ''); + $I->seeTableRowCheckboxesAreUnchecked('user_group_form_users_'); // All checkboxes are unchecked + $I->seeTableRowCheckboxesAreUnchecked('user_group_form_permissions_'); // All checkboxes are unchecked + + // Fill form + $I->fillField('User group name', 'All'); + $I->fillField('User group description', 'All users'); + + $I->checkTableRowCheckbox(AdminFixture::ID); + $I->checkTableRowCheckbox(User1Fixture::ID); + $I->checkTableRowCheckbox(User2Fixture::ID); + $I->checkTableRowCheckbox(User3Fixture::ID); + + $I->checkOption('Can list users'); + $I->checkOption('Can edit users'); + $I->checkOption('Can delete users'); + + $I->checkOption('Can list user groups'); + $I->checkOption('Can create user groups'); + $I->checkOption('Can edit user groups'); + $I->checkOption('Can delete user groups'); + + $I->checkOption('Can list mods'); + $I->checkOption('Can create mods'); + $I->checkOption('Can edit mods'); + $I->checkOption('Can delete mods'); + $I->checkOption('Can change mods status'); + + $I->checkOption('Can list mod groups'); + $I->checkOption('Can create mod groups'); + $I->checkOption('Can edit mod groups'); + $I->checkOption('Can delete mod groups'); + + $I->checkOption('Can list DLCs'); + $I->checkOption('Can create DLCs'); + $I->checkOption('Can edit DLCs'); + $I->checkOption('Can delete DLCs'); + + $I->checkOption('Can list mod lists'); + $I->checkOption('Can create mod lists'); + $I->checkOption('Can edit other users mod lists'); + $I->checkOption('Can copy mod lists'); + $I->checkOption('Can delete other users mod lists'); + $I->checkOption('Can approve mod lists'); + $I->click('Create user group'); + + $I->seeResponseRedirectsTo('/user-group/list'); + + /** @var UserGroup $userGroup */ + $userGroup = $I->grabEntityFromRepository(UserGroup::class, ['name' => 'All']); + $I->assertSame('All', $userGroup->getName()); + $I->assertSame('All users', $userGroup->getDescription()); + $I->assertSame([ + AdminFixture::ID, + User1Fixture::ID, + User2Fixture::ID, + User3Fixture::ID, + ], array_map(fn (User $user) => $user->getId()->toString(), $userGroup->getUsers())); + + $I->assertTrue($userGroup->getPermissions()->userList); + $I->assertTrue($userGroup->getPermissions()->userUpdate); + $I->assertTrue($userGroup->getPermissions()->userDelete); + + $I->assertTrue($userGroup->getPermissions()->userGroupList); + $I->assertTrue($userGroup->getPermissions()->userGroupCreate); + $I->assertTrue($userGroup->getPermissions()->userGroupUpdate); + $I->assertTrue($userGroup->getPermissions()->userGroupDelete); + + $I->assertTrue($userGroup->getPermissions()->modList); + $I->assertTrue($userGroup->getPermissions()->modCreate); + $I->assertTrue($userGroup->getPermissions()->modUpdate); + $I->assertTrue($userGroup->getPermissions()->modDelete); + $I->assertTrue($userGroup->getPermissions()->modChangeStatus); + + $I->assertTrue($userGroup->getPermissions()->modGroupList); + $I->assertTrue($userGroup->getPermissions()->modGroupCreate); + $I->assertTrue($userGroup->getPermissions()->modGroupUpdate); + $I->assertTrue($userGroup->getPermissions()->modGroupDelete); + + $I->assertTrue($userGroup->getPermissions()->dlcList); + $I->assertTrue($userGroup->getPermissions()->dlcCreate); + $I->assertTrue($userGroup->getPermissions()->dlcUpdate); + $I->assertTrue($userGroup->getPermissions()->dlcDelete); + + $I->assertTrue($userGroup->getPermissions()->modListList); + $I->assertTrue($userGroup->getPermissions()->modListCreate); + $I->assertTrue($userGroup->getPermissions()->modListUpdate); + $I->assertTrue($userGroup->getPermissions()->modListCopy); + $I->assertTrue($userGroup->getPermissions()->modListDelete); + $I->assertTrue($userGroup->getPermissions()->modListApprove); + + $I->assertSame('2020-01-01T00:00:00+00:00', $userGroup->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $userGroup->getCreatedBy()?->getId()->toString()); + $I->assertSame(null, $userGroup->getLastUpdatedAt()); + $I->assertSame(null, $userGroup->getLastUpdatedBy()?->getId()->toString()); + } + + public function createUserGroupAsAuthorizedUserWhenUserGroupAlreadyExists(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userGroupCreate = true; + }); + + $I->amOnPage('/user-group/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('User group name', UsersGroupFixture::NAME); + $I->click('Create user group'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'User group with the same name "Users" already exist.'); + } + + public function createUserGroupAsAuthorizedUserWithoutRequiredData(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userGroupCreate = true; + }); + + $I->amOnPage('/user-group/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('User group name', ''); + $I->click('Create user group'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'This value should not be blank.'); + } + + public function createUserGroupAsAuthorizedUserWithDataTooLong(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userGroupCreate = true; + }); + + $I->amOnPage('/user-group/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('User group name', str_repeat('a', 256)); + $I->fillField('User group description', str_repeat('a', 256)); + $I->click('Create user group'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'This value is too long. It should have 255 characters or less.'); + $I->seeFormErrorMessage('description', 'This value is too long. It should have 255 characters or less.'); + } +} diff --git a/tests/functional/Web/UserGroup/DeleteUserGroupCest.php b/tests/functional/Web/UserGroup/DeleteUserGroupCest.php new file mode 100644 index 00000000..30be0179 --- /dev/null +++ b/tests/functional/Web/UserGroup/DeleteUserGroupCest.php @@ -0,0 +1,64 @@ +stopFollowingRedirects(); + } + + public function deleteUserGroupAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage(sprintf('/user-group/%s/delete', UsersGroupFixture::NAME)); + + $I->seeResponseRedirectsToLogInAction(); + + $I->seeInRepository(UserGroup::class, ['name' => UsersGroupFixture::NAME]); + } + + public function deleteUserGroupAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage(sprintf('/user-group/%s/delete', UsersGroupFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + + $I->seeInRepository(UserGroup::class, ['name' => UsersGroupFixture::NAME]); + } + + public function deleteUserGroupAsAuthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userGroupDelete = true; + }); + + $I->amOnPage(sprintf('/user-group/%s/delete', UsersGroupFixture::NAME)); + + $I->seeResponseRedirectsTo('/user-group/list'); + + $I->dontSeeInRepository(UserGroup::class, ['name' => UsersGroupFixture::NAME]); + } + + public function deleteUserGroupAsAuthorizedUserWhenUserGroupDoesNotExist(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userGroupDelete = true; + }); + + $I->amOnPage(sprintf('/user-group/%s/delete', 'non existing')); + + $I->seeResponseCodeIs(HttpCode::NOT_FOUND); + } +} diff --git a/tests/functional/Web/UserGroup/ListUserGroupsCest.php b/tests/functional/Web/UserGroup/ListUserGroupsCest.php new file mode 100644 index 00000000..9c616053 --- /dev/null +++ b/tests/functional/Web/UserGroup/ListUserGroupsCest.php @@ -0,0 +1,97 @@ +stopFollowingRedirects(); + } + + public function listUserGroupsAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage('/user-group/list'); + + $I->seeResponseRedirectsToLogInAction(); + } + + public function listUserGroupsAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage('/user-group/list'); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + } + + public function listUserGroupsAsAuthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userGroupList = true; + }); + + $I->amOnPage('/user-group/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->dontSeeLink('Create user group'); + $I->dontSeeActionButton('Edit user group'); + $I->dontSeeActionButton('Delete user group'); + } + + public function listUserGroupsAsAuthorizedUserWithCreateModPermission(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userGroupList = true; + $user->getPermissions()->userGroupCreate = true; + }); + + $I->amOnPage('/user-group/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeLink('Create user group'); + $I->dontSeeActionButton('Edit user group'); + $I->dontSeeActionButton('Delete user group'); + } + + public function listUserGroupsAsAuthorizedUserWithUpdateModPermission(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userGroupList = true; + $user->getPermissions()->userGroupUpdate = true; + }); + + $I->amOnPage('/user-group/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->dontSeeLink('Create user group'); + $I->seeActionButton('Edit user group'); + $I->dontSeeActionButton('Delete user group'); + } + + public function listUserGroupsAsAuthorizedUserWithDeleteModPermission(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userGroupList = true; + $user->getPermissions()->userGroupDelete = true; + }); + + $I->amOnPage('/user-group/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->dontSeeLink('Create user group'); + $I->dontSeeActionButton('Edit user group'); + $I->seeActionButton('Delete user group'); + } +} diff --git a/tests/functional/Web/UserGroup/UpdateUserGroupCest.php b/tests/functional/Web/UserGroup/UpdateUserGroupCest.php new file mode 100644 index 00000000..1be21ae2 --- /dev/null +++ b/tests/functional/Web/UserGroup/UpdateUserGroupCest.php @@ -0,0 +1,191 @@ +stopFollowingRedirects(); + $I->freezeTime('2021-01-01T00:00:00+00:00'); + } + + public function updateUserGroupAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage(sprintf('/user-group/%s/update', UsersGroupFixture::NAME)); + + $I->seeResponseRedirectsToLogInAction(); + } + + public function updateUserGroupAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage(sprintf('/user-group/%s/update', UsersGroupFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + } + + public function updateUserGroupAsAuthorizedUser(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userGroupUpdate = true; + }); + + $I->amOnPage(sprintf('/user-group/%s/update', UsersGroupFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeInField('User group name', 'Users'); + $I->seeInField('User group description', ''); + $I->seeTableRowCheckboxesAreUnchecked('user_group_form_users_', [ + User1Fixture::ID, + User2Fixture::ID, + User3Fixture::ID, + ]); // Some checkboxes checked + $I->seeTableRowCheckboxesAreUnchecked('user_group_form_permissions_'); // Some checkboxes checked + + // Fill form + $I->fillField('User group name', 'All'); + $I->fillField('User group description', 'All users'); + $I->checkTableRowCheckbox(AdminFixture::ID); + $I->checkOption('Can list users'); + $I->checkOption('Can list user groups'); + $I->checkOption('Can list mods'); + $I->checkOption('Can list mod groups'); + $I->checkOption('Can list DLCs'); + $I->checkOption('Can list mod lists'); + $I->click('Apply'); + + $I->seeResponseRedirectsTo('/user-group/list'); + + /** @var UserGroup $userGroup */ + $userGroup = $I->grabEntityFromRepository(UserGroup::class, ['name' => 'All']); + $I->assertSame('All', $userGroup->getName()); + $I->assertSame('All users', $userGroup->getDescription()); + $I->assertSame([ + User1Fixture::ID, + User2Fixture::ID, + User3Fixture::ID, + AdminFixture::ID, + ], array_map(fn (User $user) => $user->getId()->toString(), $userGroup->getUsers())); + + $I->assertTrue($userGroup->getPermissions()->userList); + $I->assertFalse($userGroup->getPermissions()->userUpdate); + $I->assertFalse($userGroup->getPermissions()->userDelete); + + $I->assertTrue($userGroup->getPermissions()->userGroupList); + $I->assertFalse($userGroup->getPermissions()->userGroupCreate); + $I->assertFalse($userGroup->getPermissions()->userGroupUpdate); + $I->assertFalse($userGroup->getPermissions()->userGroupDelete); + + $I->assertTrue($userGroup->getPermissions()->modList); + $I->assertFalse($userGroup->getPermissions()->modCreate); + $I->assertFalse($userGroup->getPermissions()->modUpdate); + $I->assertFalse($userGroup->getPermissions()->modDelete); + $I->assertFalse($userGroup->getPermissions()->modChangeStatus); + + $I->assertTrue($userGroup->getPermissions()->modGroupList); + $I->assertFalse($userGroup->getPermissions()->modGroupCreate); + $I->assertFalse($userGroup->getPermissions()->modGroupUpdate); + $I->assertFalse($userGroup->getPermissions()->modGroupDelete); + + $I->assertTrue($userGroup->getPermissions()->dlcList); + $I->assertFalse($userGroup->getPermissions()->dlcCreate); + $I->assertFalse($userGroup->getPermissions()->dlcUpdate); + $I->assertFalse($userGroup->getPermissions()->dlcDelete); + + $I->assertTrue($userGroup->getPermissions()->modListList); + $I->assertFalse($userGroup->getPermissions()->modListCreate); + $I->assertFalse($userGroup->getPermissions()->modListUpdate); + $I->assertFalse($userGroup->getPermissions()->modListCopy); + $I->assertFalse($userGroup->getPermissions()->modListDelete); + $I->assertFalse($userGroup->getPermissions()->modListApprove); + + $I->assertSame('2020-01-01T00:00:00+00:00', $userGroup->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame(null, $userGroup->getCreatedBy()?->getId()->toString()); + $I->assertSame('2021-01-01T00:00:00+00:00', $userGroup->getLastUpdatedAt()?->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $userGroup->getLastUpdatedBy()?->getId()->toString()); + } + + public function updateUserGroupAsAuthorizedUserWhenUserGroupAlreadyExists(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userGroupUpdate = true; + }); + + $I->amOnPage(sprintf('/user-group/%s/update', UsersGroupFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('User group name', AdminsGroupFixture::NAME); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'User group with the same name "Admins" already exist.'); + } + + public function updateUserGroupAsAuthorizedUserWithoutRequiredData(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userGroupUpdate = true; + }); + + $I->amOnPage(sprintf('/user-group/%s/update', UsersGroupFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('User group name', ''); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'This value should not be blank.'); + } + + public function updateUserGroupAsAuthorizedUserWithDataTooLong(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userGroupUpdate = true; + }); + + $I->amOnPage(sprintf('/user-group/%s/update', UsersGroupFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('User group name', str_repeat('a', 256)); + $I->fillField('User group description', str_repeat('a', 256)); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'This value is too long. It should have 255 characters or less.'); + $I->seeFormErrorMessage('description', 'This value is too long. It should have 255 characters or less.'); + } + + public function updateUserGroupAsAuthorizedUserWhenUserGroupDoesNotExist(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->userGroupUpdate = true; + }); + + $I->amOnPage(sprintf('/user-group/%s/update', 'non existing')); + + $I->seeResponseCodeIs(HttpCode::NOT_FOUND); + } +} From aa2ff2c2634c7b186aafcda2d0338057517d7134 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Skowro=C5=84ski?= Date: Wed, 10 Jan 2024 22:52:43 +0100 Subject: [PATCH 11/17] Add DLC tests --- tests/functional/Web/Dlc/CreateDlcCest.php | 255 ++++++++++++++++++++ tests/functional/Web/Dlc/DeleteDlcCest.php | 64 +++++ tests/functional/Web/Dlc/ListDlcsCest.php | 96 ++++++++ tests/functional/Web/Dlc/UpdateDlcCest.php | 268 +++++++++++++++++++++ 4 files changed, 683 insertions(+) create mode 100644 tests/functional/Web/Dlc/CreateDlcCest.php create mode 100644 tests/functional/Web/Dlc/DeleteDlcCest.php create mode 100644 tests/functional/Web/Dlc/ListDlcsCest.php create mode 100644 tests/functional/Web/Dlc/UpdateDlcCest.php diff --git a/tests/functional/Web/Dlc/CreateDlcCest.php b/tests/functional/Web/Dlc/CreateDlcCest.php new file mode 100644 index 00000000..5759adbe --- /dev/null +++ b/tests/functional/Web/Dlc/CreateDlcCest.php @@ -0,0 +1,255 @@ +stopFollowingRedirects(); + $I->freezeTime('2020-01-01T00:00:00+00:00'); + } + + public function createDlcAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage('/dlc/create'); + + $I->seeResponseRedirectsToLogInAction(); + } + + public function createDlcAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage('/dlc/create'); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + } + + public function createDlcAsAuthorizedUser(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcCreate = true; + }); + + $I->amOnPage('/dlc/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeInField('Steam Store URL', ''); + $I->seeInField('DLC directory', ''); + $I->seeInField('DLC name', ''); + $I->seeInField('DLC description', ''); + + // Fill form + $I->fillField('Steam Store URL', 'https://store.steampowered.com/app/1681170/Arma_3_Creator_DLC_Western_Sahara'); + $I->fillField('DLC directory', 'ws'); + $I->fillField('DLC name', 'Western Sahara'); + $I->fillField('DLC description', 'Western Sahara Arma 3 DLC'); + $I->click('Create DLC'); + + $I->seeResponseRedirectsTo('/dlc/list'); + + /** @var Dlc $dlc */ + $dlc = $I->grabEntityFromRepository(Dlc::class, ['appId' => 1681170]); + $I->assertSame(1681170, $dlc->getAppId()); + $I->assertSame('ws', $dlc->getDirectory()); + $I->assertSame('Western Sahara', $dlc->getName()); + $I->assertSame('Western Sahara Arma 3 DLC', $dlc->getDescription()); + + $I->assertSame('2020-01-01T00:00:00+00:00', $dlc->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $dlc->getCreatedBy()?->getId()->toString()); + $I->assertSame(null, $dlc->getLastUpdatedAt()); + $I->assertSame(null, $dlc->getLastUpdatedBy()?->getId()->toString()); + } + + public function createDlcAsAuthorizedUserWithNameProvidedBySteamWorkshop(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcCreate = true; + }); + + $I->amOnPage('/dlc/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeInField('Steam Store URL', ''); + $I->seeInField('DLC directory', ''); + $I->seeInField('DLC name', ''); + $I->seeInField('DLC description', ''); + + // Fill form + $I->fillField('Steam Store URL', 'https://store.steampowered.com/app/1681170/Arma_3_Creator_DLC_Western_Sahara'); + $I->fillField('DLC directory', 'ws'); + $I->fillField('DLC name', ''); + $I->fillField('DLC description', ''); + $I->click('Create DLC'); + + $I->seeResponseRedirectsTo('/dlc/list'); + + /** @var Dlc $dlc */ + $dlc = $I->grabEntityFromRepository(Dlc::class, ['appId' => 1681170]); + $I->assertSame(1681170, $dlc->getAppId()); + $I->assertSame('ws', $dlc->getDirectory()); + $I->assertSame('Arma 3 Creator DLC: Western Sahara', $dlc->getName()); // From Steam Workshop + $I->assertSame(null, $dlc->getDescription()); + + $I->assertSame('2020-01-01T00:00:00+00:00', $dlc->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $dlc->getCreatedBy()?->getId()->toString()); + $I->assertSame(null, $dlc->getLastUpdatedAt()); + $I->assertSame(null, $dlc->getLastUpdatedBy()?->getId()->toString()); + } + + public function createDlcAsAuthorizedUserWhenDlcAlreadyExists(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcCreate = true; + }); + + $I->amOnPage('/dlc/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $url = 'https://store.steampowered.com/app/1227700/Arma_3_Creator_DLC_SOG_Prairie_Fire/'; + $I->fillField('Steam Store URL', $url); + $I->fillField('DLC directory', 'vn'); + $I->click('Create DLC'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $message = sprintf('DLC associated with url "%s" already exist.', $url); + $I->seeFormErrorMessage('url', $message); + $I->seeFormErrorMessage('directory', 'DLC associated with directory "vn" already exist.'); + } + + public function createDlcAsAuthorizedUserWithInvalidDlcUrl(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcCreate = true; + }); + + $I->amOnPage('/dlc/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Steam Store URL', 'https://example.com'); + $I->fillField('DLC directory', 'ws'); + $I->click('Create DLC'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('url', 'Invalid Steam Store DLC url.'); + } + + public function createDlcAsAuthorizedUserWhenDlcDoesNotExist(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcCreate = true; + }); + + $I->amOnPage('/dlc/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $url = SteamHelper::appIdToAppUrl(9999999); + $I->fillField('Steam Store URL', $url); + $I->fillField('DLC directory', 'ws'); + $I->click('Create DLC'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('url', 'DLC not found.'); + } + + public function createDlcAsAuthorizedUserWhenUrlIsNotAnArma3Dlc(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcCreate = true; + }); + + $I->amOnPage('/dlc/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $url = SteamHelper::appIdToAppUrl(2138330); + $I->fillField('Steam Store URL', $url); + $I->fillField('DLC directory', 'ws'); + $I->click('Create DLC'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('url', 'Url is not an Arma 3 DLC.'); + } + + public function createDlcAsAuthorizedUserWithInvalidDirectoryName(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcCreate = true; + }); + + $I->amOnPage('/dlc/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Steam Store URL', 'https://store.steampowered.com/app/1681170/Arma_3_Creator_DLC_Western_Sahara'); + $I->fillField('DLC directory', 'w/s'); + $I->click('Create DLC'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('directory', 'Invalid directory name.'); + } + + public function createDlcAsAuthorizedUserWithoutRequiredData(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcCreate = true; + }); + + $I->amOnPage('/dlc/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Steam Store URL', ''); + $I->fillField('DLC directory', ''); + $I->click('Create DLC'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('url', 'This value should not be blank.'); + $I->seeFormErrorMessage('directory', 'This value should not be blank.'); + } + + public function createDlcAsAuthorizedUserWithDataTooLong(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcCreate = true; + }); + + $I->amOnPage('/dlc/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Steam Store URL', 'https://store.steampowered.com/app/1681170/Arma_3_Creator_DLC_Western_Sahara'); + $I->fillField('DLC directory', 'ws'); + $I->fillField('DLC name', str_repeat('a', 256)); + $I->fillField('DLC description', str_repeat('a', 256)); + $I->click('Create DLC'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'This value is too long. It should have 255 characters or less.'); + $I->seeFormErrorMessage('description', 'This value is too long. It should have 255 characters or less.'); + } +} diff --git a/tests/functional/Web/Dlc/DeleteDlcCest.php b/tests/functional/Web/Dlc/DeleteDlcCest.php new file mode 100644 index 00000000..d9ad29c3 --- /dev/null +++ b/tests/functional/Web/Dlc/DeleteDlcCest.php @@ -0,0 +1,64 @@ +stopFollowingRedirects(); + } + + public function deleteDlcAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage(sprintf('/dlc/%s/delete', SogPrairieFireDlcFixture::ID)); + + $I->seeResponseRedirectsToLogInAction(); + + $I->seeInRepository(Dlc::class, ['id' => SogPrairieFireDlcFixture::ID]); + } + + public function deleteDlcAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage(sprintf('/dlc/%s/delete', SogPrairieFireDlcFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + + $I->seeInRepository(Dlc::class, ['id' => SogPrairieFireDlcFixture::ID]); + } + + public function deleteDlcAsAuthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcDelete = true; + }); + + $I->amOnPage(sprintf('/dlc/%s/delete', SogPrairieFireDlcFixture::ID)); + + $I->seeResponseRedirectsTo('/dlc/list'); + + $I->dontSeeInRepository(Dlc::class, ['id' => SogPrairieFireDlcFixture::ID]); + } + + public function deleteDlcAsAuthorizedUserWhenDlcDoesNotExist(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcDelete = true; + }); + + $I->amOnPage(sprintf('/dlc/%s/delete', 'd2cca3c6-1c5f-4ea7-afcf-a05317a58467')); + + $I->seeResponseCodeIs(HttpCode::NOT_FOUND); + } +} diff --git a/tests/functional/Web/Dlc/ListDlcsCest.php b/tests/functional/Web/Dlc/ListDlcsCest.php new file mode 100644 index 00000000..736a50b9 --- /dev/null +++ b/tests/functional/Web/Dlc/ListDlcsCest.php @@ -0,0 +1,96 @@ +stopFollowingRedirects(); + } + + public function listDlcsAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage('/dlc/list'); + + $I->seeResponseRedirectsToLogInAction(); + } + + public function listDlcsAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage('/dlc/list'); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + } + + public function listDlcsAsAuthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcList = true; + }); + + $I->amOnPage('/dlc/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->dontSeeActionButton('Create DLC'); + $I->dontSeeActionButton('Edit DLC'); + } + + public function listDlcsAsAuthorizedUserWithCreateDlcPermission(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcList = true; + $user->getPermissions()->dlcCreate = true; + }); + + $I->amOnPage('/dlc/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeLink('Create DLC'); + $I->dontSeeActionButton('Edit DLC'); + $I->dontSeeActionButton('Delete DLC'); + } + + public function listDlcsAsAuthorizedUserWithUpdateDlcPermission(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcList = true; + $user->getPermissions()->dlcUpdate = true; + }); + + $I->amOnPage('/dlc/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->dontSeeLink('Create DLC'); + $I->seeActionButton('Edit DLC'); + $I->dontSeeActionButton('Delete DLC'); + } + + public function listDlcsAsAuthorizedUserWithDeleteDlcPermission(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcList = true; + $user->getPermissions()->dlcDelete = true; + }); + + $I->amOnPage('/dlc/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->dontSeeLink('Create DLC'); + $I->dontSeeActionButton('Edit DLC'); + $I->seeActionButton('Delete DLC'); + } +} diff --git a/tests/functional/Web/Dlc/UpdateDlcCest.php b/tests/functional/Web/Dlc/UpdateDlcCest.php new file mode 100644 index 00000000..b5e236ef --- /dev/null +++ b/tests/functional/Web/Dlc/UpdateDlcCest.php @@ -0,0 +1,268 @@ +stopFollowingRedirects(); + $I->freezeTime('2021-01-01T00:00:00+00:00'); + } + + public function updateDlcAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage(sprintf('/dlc/%s/update', SogPrairieFireDlcFixture::ID)); + + $I->seeResponseRedirectsToLogInAction(); + } + + public function updateDlcAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage(sprintf('/dlc/%s/update', SogPrairieFireDlcFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + } + + public function updateDlcAsAuthorizedUser(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcUpdate = true; + }); + + $I->amOnPage(sprintf('/dlc/%s/update', SogPrairieFireDlcFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeInField('Steam Store URL', 'https://store.steampowered.com/app/1227700'); + $I->seeInField('DLC directory', 'vn'); + $I->seeInField('DLC name', 'Arma 3 Creator DLC: S.O.G. Prairie Fire'); + $I->seeInField('DLC description', ''); + + // Fill form + $I->fillField('Steam Store URL', 'https://store.steampowered.com/app/1681170/Arma_3_Creator_DLC_Western_Sahara'); + $I->fillField('DLC directory', 'ws'); + $I->fillField('DLC name', 'Western Sahara'); + $I->fillField('DLC description', 'Western Sahara Arma 3 DLC'); + $I->click('Apply'); + + $I->seeResponseRedirectsTo('/dlc/list'); + + /** @var Dlc $dlc */ + $dlc = $I->grabEntityFromRepository(Dlc::class, ['appId' => 1681170]); + $I->assertSame(1681170, $dlc->getAppId()); + $I->assertSame('ws', $dlc->getDirectory()); + $I->assertSame('Western Sahara', $dlc->getName()); + $I->assertSame('Western Sahara Arma 3 DLC', $dlc->getDescription()); + + $I->assertSame('2020-01-01T00:00:00+00:00', $dlc->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame(null, $dlc->getCreatedBy()?->getId()->toString()); + $I->assertSame('2021-01-01T00:00:00+00:00', $dlc->getLastUpdatedAt()?->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $dlc->getLastUpdatedBy()?->getId()->toString()); + } + + public function updateDlcAsAuthorizedUserWithNameProvidedBySteamWorkshop(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcUpdate = true; + }); + + $I->amOnPage(sprintf('/dlc/%s/update', SogPrairieFireDlcFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeInField('Steam Store URL', 'https://store.steampowered.com/app/1227700'); + $I->seeInField('DLC directory', 'vn'); + $I->seeInField('DLC name', 'Arma 3 Creator DLC: S.O.G. Prairie Fire'); + $I->seeInField('DLC description', ''); + + // Fill form + $I->fillField('Steam Store URL', 'https://store.steampowered.com/app/1681170/Arma_3_Creator_DLC_Western_Sahara'); + $I->fillField('DLC directory', 'ws'); + $I->fillField('DLC name', ''); + $I->fillField('DLC description', ''); + $I->click('Apply'); + + $I->seeResponseRedirectsTo('/dlc/list'); + + /** @var Dlc $dlc */ + $dlc = $I->grabEntityFromRepository(Dlc::class, ['appId' => 1681170]); + $I->assertSame(1681170, $dlc->getAppId()); + $I->assertSame('ws', $dlc->getDirectory()); + $I->assertSame('Arma 3 Creator DLC: Western Sahara', $dlc->getName()); // From Steam Workshop + $I->assertSame(null, $dlc->getDescription()); + + $I->assertSame('2020-01-01T00:00:00+00:00', $dlc->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame(null, $dlc->getCreatedBy()?->getId()->toString()); + $I->assertSame('2021-01-01T00:00:00+00:00', $dlc->getLastUpdatedAt()?->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $dlc->getLastUpdatedBy()?->getId()->toString()); + } + + public function updateDlcAsAuthorizedUserWhenDlcAlreadyExists(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcUpdate = true; + }); + + $I->amOnPage(sprintf('/dlc/%s/update', CslaIronCurtainDlcFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $url = 'https://store.steampowered.com/app/1227700/Arma_3_Creator_DLC_SOG_Prairie_Fire/'; + $I->fillField('Steam Store URL', $url); + $I->fillField('DLC directory', 'vn'); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $message = sprintf('DLC associated with url "%s" already exist.', $url); + $I->seeFormErrorMessage('url', $message); + $I->seeFormErrorMessage('directory', 'DLC associated with directory "vn" already exist.'); + } + + public function updateDlcAsAuthorizedUserWithInvalidDlcUrl(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcUpdate = true; + }); + + $I->amOnPage(sprintf('/dlc/%s/update', SogPrairieFireDlcFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Steam Store URL', 'https://example.com'); + $I->fillField('DLC directory', 'ws'); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('url', 'Invalid Steam Store DLC url.'); + } + + public function updateDlcAsAuthorizedUserWhenDlcDoesNotExistInSteamApi(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcUpdate = true; + }); + + $I->amOnPage(sprintf('/dlc/%s/update', SogPrairieFireDlcFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $url = SteamHelper::appIdToAppUrl(9999999); + $I->fillField('Steam Store URL', $url); + $I->fillField('DLC directory', 'ws'); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('url', 'DLC not found.'); + } + + public function updateDlcAsAuthorizedUserWhenUrlIsNotAnArma3Dlc(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcUpdate = true; + }); + + $I->amOnPage(sprintf('/dlc/%s/update', SogPrairieFireDlcFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $url = SteamHelper::appIdToAppUrl(2138330); + $I->fillField('Steam Store URL', $url); + $I->fillField('DLC directory', 'ws'); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('url', 'Url is not an Arma 3 DLC.'); + } + + public function updateDlcAsAuthorizedUserWithInvalidDirectoryName(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcUpdate = true; + }); + + $I->amOnPage(sprintf('/dlc/%s/update', SogPrairieFireDlcFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Steam Store URL', 'https://store.steampowered.com/app/1681170/Arma_3_Creator_DLC_Western_Sahara'); + $I->fillField('DLC directory', 'w/s'); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('directory', 'Invalid directory name.'); + } + + public function updateDlcAsAuthorizedUserWithoutRequiredData(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcUpdate = true; + }); + + $I->amOnPage(sprintf('/dlc/%s/update', SogPrairieFireDlcFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Steam Store URL', ''); + $I->fillField('DLC directory', ''); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('url', 'This value should not be blank.'); + $I->seeFormErrorMessage('directory', 'This value should not be blank.'); + } + + public function updateDlcAsAuthorizedUserWithDataTooLong(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcUpdate = true; + }); + + $I->amOnPage(sprintf('/dlc/%s/update', SogPrairieFireDlcFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Steam Store URL', 'https://store.steampowered.com/app/1681170/Arma_3_Creator_DLC_Western_Sahara'); + $I->fillField('DLC directory', 'ws'); + $I->fillField('DLC name', str_repeat('a', 256)); + $I->fillField('DLC description', str_repeat('a', 256)); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'This value is too long. It should have 255 characters or less.'); + $I->seeFormErrorMessage('description', 'This value is too long. It should have 255 characters or less.'); + } + + public function updateDlcAsAuthorizedUserWhenDlcDoesNotExist(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->dlcUpdate = true; + }); + + $I->amOnPage(sprintf('/dlc/%s/update', 'd2cca3c6-1c5f-4ea7-afcf-a05317a58467')); + + $I->seeResponseCodeIs(HttpCode::NOT_FOUND); + } +} From 396b4fdf5063acfe7b79365223c9234cc43d4a24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Skowro=C5=84ski?= Date: Wed, 10 Jan 2024 22:52:57 +0100 Subject: [PATCH 12/17] Add mod tests --- .../Web/Mod/CreateDirectoryModCest.php | 199 ++++++++++++ .../Web/Mod/CreateSteamWorkshopModCest.php | 280 +++++++++++++++++ tests/functional/Web/Mod/DeleteModCest.php | 64 ++++ tests/functional/Web/Mod/ListModsCest.php | 97 ++++++ .../Web/Mod/UpdateDirectoryModCest.php | 209 +++++++++++++ .../Web/Mod/UpdateSteamWorkshopModCest.php | 289 ++++++++++++++++++ 6 files changed, 1138 insertions(+) create mode 100644 tests/functional/Web/Mod/CreateDirectoryModCest.php create mode 100644 tests/functional/Web/Mod/CreateSteamWorkshopModCest.php create mode 100644 tests/functional/Web/Mod/DeleteModCest.php create mode 100644 tests/functional/Web/Mod/ListModsCest.php create mode 100644 tests/functional/Web/Mod/UpdateDirectoryModCest.php create mode 100644 tests/functional/Web/Mod/UpdateSteamWorkshopModCest.php diff --git a/tests/functional/Web/Mod/CreateDirectoryModCest.php b/tests/functional/Web/Mod/CreateDirectoryModCest.php new file mode 100644 index 00000000..e7ba4b05 --- /dev/null +++ b/tests/functional/Web/Mod/CreateDirectoryModCest.php @@ -0,0 +1,199 @@ +stopFollowingRedirects(); + $I->freezeTime('2020-01-01T00:00:00+00:00'); + } + + public function createDirectoryModAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage('/mod/create'); + + $I->seeResponseRedirectsToLogInAction(); + } + + public function createDirectoryModAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage('/mod/create'); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + } + + public function createDirectoryModAsAuthorizedUser(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modCreate = true; + }); + + $I->amOnPage('/mod/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeOptionIsSelected('Mod source', 'Steam Workshop'); + $I->seeInField('Mod directory', ''); + $I->dontSee('Mod status'); // Not visible + $I->seeInField('Mod name', ''); + $I->seeInField('Mod description', ''); + + // Fill form + $I->selectOption('Mod source', 'Directory'); + $I->fillField('Mod directory', '@OCAP'); + $I->fillField('Mod name', 'OCAP'); + $I->fillField('Mod description', 'OCAP - AAR'); + $I->click('Create mod'); + + $I->seeResponseRedirectsTo('/mod/list'); + + /** @var DirectoryMod $mod */ + $mod = $I->grabEntityFromRepository(DirectoryMod::class, ['directory' => '@OCAP']); + $I->assertSame(null, $mod->getStatus()); + $I->assertSame('OCAP', $mod->getName()); + $I->assertSame('OCAP - AAR', $mod->getDescription()); + + $I->assertSame('2020-01-01T00:00:00+00:00', $mod->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $mod->getCreatedBy()?->getId()->toString()); + $I->assertSame(null, $mod->getLastUpdatedAt()); + $I->assertSame(null, $mod->getLastUpdatedBy()?->getId()->toString()); + } + + public function createDirectoryModAsAuthorizedUserWithChangeModStatusPermission(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modCreate = true; + $user->getPermissions()->modChangeStatus = true; + }); + + $I->amOnPage('/mod/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeOptionIsSelected('Mod source', 'Steam Workshop'); + $I->seeInField('Mod directory', ''); + $I->seeOptionIsSelected('Mod status', ''); + $I->seeInField('Mod name', ''); + $I->seeInField('Mod description', ''); + + // Fill form + $I->selectOption('Mod source', 'Directory'); + $I->fillField('Mod directory', '@OCAP'); + $I->selectOption('Mod status', 'Deprecated'); + $I->fillField('Mod name', 'OCAP'); + $I->fillField('Mod description', 'OCAP - AAR'); + $I->click('Create mod'); + + $I->seeResponseRedirectsTo('/mod/list'); + + /** @var DirectoryMod $mod */ + $mod = $I->grabEntityFromRepository(DirectoryMod::class, ['directory' => '@OCAP']); + $I->assertSame(ModStatusEnum::DEPRECATED, $mod->getStatus()); + $I->assertSame('OCAP', $mod->getName()); + $I->assertSame('OCAP - AAR', $mod->getDescription()); + + $I->assertSame('2020-01-01T00:00:00+00:00', $mod->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $mod->getCreatedBy()?->getId()->toString()); + $I->assertSame(null, $mod->getLastUpdatedAt()); + $I->assertSame(null, $mod->getLastUpdatedBy()?->getId()->toString()); + } + + public function createDirectoryModAsAuthorizedUserWhenModAlreadyExists(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modCreate = true; + }); + + $I->amOnPage('/mod/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->selectOption('Mod source', 'Directory'); + $I->fillField('Mod directory', ArmaScriptProfilerModFixture::DIRECTORY); + $I->fillField('Mod name', 'Arma Script Profiler'); + $I->click('Create mod'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->canSeeFormErrorMessage('directory', 'Mod associated with directory "@Arma Script Profiler" already exist.'); + } + + public function createDirectoryModAsAuthorizedUserWithInvalidDirectoryName(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modCreate = true; + }); + + $I->amOnPage('/mod/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->selectOption('Mod source', 'Directory'); + $I->fillField('Mod directory', '@OC/AP'); + $I->fillField('Mod name', 'OCAP'); + $I->click('Create mod'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->canSeeFormErrorMessage('directory', 'Invalid directory name.'); + } + + public function createDirectoryModAsAuthorizedUserWithoutRequiredData(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modCreate = true; + }); + + $I->amOnPage('/mod/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->selectOption('Mod source', 'Directory'); + $I->fillField('Mod directory', ''); + $I->fillField('Mod name', ''); + $I->click('Create mod'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->canSeeFormErrorMessage('directory', 'This value should not be blank.'); + $I->canSeeFormErrorMessage('name', 'This value should not be blank.'); + } + + public function createDirectoryModAsAuthorizedUserWithDataTooLong(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modCreate = true; + }); + + $I->amOnPage('/mod/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->selectOption('Mod source', 'Directory'); + $I->fillField('Mod directory', '@OCAP'); + $I->fillField('Mod name', str_repeat('a', 256)); + $I->fillField('Mod description', str_repeat('a', 256)); + $I->click('Create mod'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->canSeeFormErrorMessage('name', 'This value is too long. It should have 255 characters or less.'); + $I->canSeeFormErrorMessage('description', 'This value is too long. It should have 255 characters or less.'); + } +} diff --git a/tests/functional/Web/Mod/CreateSteamWorkshopModCest.php b/tests/functional/Web/Mod/CreateSteamWorkshopModCest.php new file mode 100644 index 00000000..5555ccf1 --- /dev/null +++ b/tests/functional/Web/Mod/CreateSteamWorkshopModCest.php @@ -0,0 +1,280 @@ +stopFollowingRedirects(); + $I->freezeTime('2020-01-01T00:00:00+00:00'); + } + + public function createSteamWorkshopModAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage('/mod/create'); + + $I->seeResponseRedirectsToLogInAction(); + } + + public function createSteamWorkshopModAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage('/mod/create'); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + } + + public function createSteamWorkshopModAsAuthorizedUser(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modCreate = true; + }); + + $I->amOnPage('/mod/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeOptionIsSelected('Mod source', 'Steam Workshop'); + $I->seeInField('Steam Workshop URL', ''); + $I->seeOptionIsSelected('Mod type', 'Required mod'); + $I->dontSee('Mod status'); // Not visible + $I->seeInField('Mod name', ''); + $I->seeInField('Mod description', ''); + + // Fill form + $I->selectOption('Mod source', 'Steam Workshop'); + $I->fillField('Steam Workshop URL', 'https://steamcommunity.com/sharedfiles/filedetails/?id=1934142795'); + $I->selectOption('Mod type', 'Optional mod'); + $I->fillField('Mod name', 'AF Mods'); + $I->fillField('Mod description', 'Custom Arma 3 mods'); + $I->click('Create mod'); + + $I->seeResponseRedirectsTo('/mod/list'); + + /** @var SteamWorkshopMod $mod */ + $mod = $I->grabEntityFromRepository(SteamWorkshopMod::class, ['itemId' => 1934142795]); + $I->assertSame(ModTypeEnum::OPTIONAL, $mod->getType()); + $I->assertSame(null, $mod->getStatus()); + $I->assertSame('AF Mods', $mod->getName()); + $I->assertSame('Custom Arma 3 mods', $mod->getDescription()); + + $I->assertSame('2020-01-01T00:00:00+00:00', $mod->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $mod->getCreatedBy()?->getId()->toString()); + $I->assertSame(null, $mod->getLastUpdatedAt()); + $I->assertSame(null, $mod->getLastUpdatedBy()?->getId()->toString()); + } + + public function createSteamWorkshopModAsAuthorizedUserWithNameProvidedBySteamWorkshop(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modCreate = true; + }); + + $I->amOnPage('/mod/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeOptionIsSelected('Mod source', 'Steam Workshop'); + $I->seeInField('Steam Workshop URL', ''); + $I->seeOptionIsSelected('Mod type', 'Required mod'); + $I->dontSee('Mod status'); // Not visible + $I->seeInField('Mod name', ''); + $I->seeInField('Mod description', ''); + + // Fill form + $I->selectOption('Mod source', 'Steam Workshop'); + $I->fillField('Steam Workshop URL', 'https://steamcommunity.com/sharedfiles/filedetails/?id=1934142795'); + $I->selectOption('Mod type', 'Required mod'); + $I->fillField('Mod name', ''); + $I->fillField('Mod description', ''); + $I->click('Create mod'); + + $I->seeResponseRedirectsTo('/mod/list'); + + /** @var SteamWorkshopMod $mod */ + $mod = $I->grabEntityFromRepository(SteamWorkshopMod::class, ['itemId' => 1934142795]); + $I->assertSame(ModTypeEnum::REQUIRED, $mod->getType()); + $I->assertSame(null, $mod->getStatus()); + $I->assertSame('ArmaForces - Mods', $mod->getName()); // From Steam Workshop + $I->assertSame(null, $mod->getDescription()); + + $I->assertSame('2020-01-01T00:00:00+00:00', $mod->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $mod->getCreatedBy()?->getId()->toString()); + $I->assertSame(null, $mod->getLastUpdatedAt()); + $I->assertSame(null, $mod->getLastUpdatedBy()?->getId()->toString()); + } + + public function createSteamWorkshopModAsAuthorizedUserWithChangeModStatusPermission(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modCreate = true; + $user->getPermissions()->modChangeStatus = true; + }); + + $I->amOnPage('/mod/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeOptionIsSelected('Mod source', 'Steam Workshop'); + $I->seeInField('Steam Workshop URL', ''); + $I->seeOptionIsSelected('Mod type', 'Required mod'); + $I->seeOptionIsSelected('Mod status', ''); + $I->seeInField('Mod name', ''); + $I->seeInField('Mod description', ''); + + // Fill form + $I->selectOption('Mod source', 'Steam Workshop'); + $I->fillField('Steam Workshop URL', 'https://steamcommunity.com/sharedfiles/filedetails/?id=1934142795'); + $I->selectOption('Mod type', 'Required mod'); + $I->selectOption('Mod status', 'Deprecated'); + $I->fillField('Mod name', 'AF Mods'); + $I->fillField('Mod description', 'Custom Arma 3 mods'); + $I->click('Create mod'); + + $I->seeResponseRedirectsTo('/mod/list'); + + /** @var SteamWorkshopMod $mod */ + $mod = $I->grabEntityFromRepository(SteamWorkshopMod::class, ['itemId' => 1934142795]); + $I->assertSame(ModTypeEnum::REQUIRED, $mod->getType()); + $I->assertSame(ModStatusEnum::DEPRECATED, $mod->getStatus()); + $I->assertSame('AF Mods', $mod->getName()); + $I->assertSame('Custom Arma 3 mods', $mod->getDescription()); + + $I->assertSame('2020-01-01T00:00:00+00:00', $mod->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $mod->getCreatedBy()?->getId()->toString()); + $I->assertSame(null, $mod->getLastUpdatedAt()); + $I->assertSame(null, $mod->getLastUpdatedBy()?->getId()->toString()); + } + + public function createSteamWorkshopModAsAuthorizedUserWhenModAlreadyExists(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modCreate = true; + }); + + $I->amOnPage('/mod/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $url = SteamHelper::itemIdToItemUrl(ArmaForcesMedicalModFixture::ITEM_ID); + $I->fillField('Steam Workshop URL', $url); + $I->click('Create mod'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $message = sprintf('Mod associated with url "%s" already exist.', $url); + $I->seeFormErrorMessage('url', $message); + } + + public function createSteamWorkshopModAsAuthorizedUserWithInvalidModUrl(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modCreate = true; + }); + + $I->amOnPage('/mod/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Steam Workshop URL', 'https://example.com'); + $I->click('Create mod'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('url', 'Invalid Steam Workshop mod url.'); + } + + public function createSteamWorkshopModAsAuthorizedUserWhenModDoesNotExist(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modCreate = true; + }); + + $I->amOnPage('/mod/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $url = SteamHelper::itemIdToItemUrl(9999999); + $I->fillField('Steam Workshop URL', $url); + $I->click('Create mod'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('url', 'Mod not found.'); + } + + public function createSteamWorkshopModAsAuthorizedUserWhenUrlIsNotAnArma3Mod(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modCreate = true; + }); + + $I->amOnPage('/mod/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $url = SteamHelper::itemIdToItemUrl(455312245); + $I->fillField('Steam Workshop URL', $url); + $I->click('Create mod'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('url', 'Url is not an Arma 3 mod.'); + } + + public function createSteamWorkshopModAsAuthorizedUserWithoutRequiredData(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modCreate = true; + }); + + $I->amOnPage('/mod/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Steam Workshop URL', ''); + $I->click('Create mod'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('url', 'This value should not be blank.'); + } + + public function createSteamWorkshopModAsAuthorizedUserWithDataTooLong(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modCreate = true; + }); + + $I->amOnPage('/mod/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Steam Workshop URL', 'https://steamcommunity.com/sharedfiles/filedetails/?id=1934142795'); + $I->fillField('Mod name', str_repeat('a', 256)); + $I->fillField('Mod description', str_repeat('a', 256)); + $I->click('Create mod'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'This value is too long. It should have 255 characters or less.'); + $I->seeFormErrorMessage('description', 'This value is too long. It should have 255 characters or less.'); + } +} diff --git a/tests/functional/Web/Mod/DeleteModCest.php b/tests/functional/Web/Mod/DeleteModCest.php new file mode 100644 index 00000000..5b3b954d --- /dev/null +++ b/tests/functional/Web/Mod/DeleteModCest.php @@ -0,0 +1,64 @@ +stopFollowingRedirects(); + } + + public function deleteModAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage(sprintf('/mod/%s/delete', ArmaForcesMedicalModFixture::ID)); + + $I->seeResponseRedirectsToLogInAction(); + + $I->seeInRepository(AbstractMod::class, ['id' => ArmaForcesMedicalModFixture::ID]); + } + + public function deleteModAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage(sprintf('/mod/%s/delete', ArmaForcesMedicalModFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + + $I->seeInRepository(AbstractMod::class, ['id' => ArmaForcesMedicalModFixture::ID]); + } + + public function deleteModAsAuthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modDelete = true; + }); + + $I->amOnPage(sprintf('/mod/%s/delete', ArmaForcesMedicalModFixture::ID)); + + $I->seeResponseRedirectsTo('/mod/list'); + + $I->dontSeeInRepository(AbstractMod::class, ['id' => ArmaForcesMedicalModFixture::ID]); + } + + public function deleteModAsAuthorizedUserWhenModDoesNotExist(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modDelete = true; + }); + + $I->amOnPage(sprintf('/mod/%s/delete', 'd2cca3c6-1c5f-4ea7-afcf-a05317a58467')); + + $I->seeResponseCodeIs(HttpCode::NOT_FOUND); + } +} diff --git a/tests/functional/Web/Mod/ListModsCest.php b/tests/functional/Web/Mod/ListModsCest.php new file mode 100644 index 00000000..4e4b1ff2 --- /dev/null +++ b/tests/functional/Web/Mod/ListModsCest.php @@ -0,0 +1,97 @@ +stopFollowingRedirects(); + } + + public function listModsAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage('/mod/list'); + + $I->seeResponseRedirectsToLogInAction(); + } + + public function listModsAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage('/mod/list'); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + } + + public function listModsAsAuthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modList = true; + }); + + $I->amOnPage('/mod/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->dontSeeLink('Create mod'); + $I->dontSeeActionButton('Edit mod'); + $I->dontSeeActionButton('Delete mod'); + } + + public function listModsAsAuthorizedUserWithCreateModPermission(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modList = true; + $user->getPermissions()->modCreate = true; + }); + + $I->amOnPage('/mod/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeLink('Create mod'); + $I->dontSeeActionButton('Edit mod'); + $I->dontSeeActionButton('Delete mod'); + } + + public function listModsAsAuthorizedUserWithUpdateModPermission(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modList = true; + $user->getPermissions()->modUpdate = true; + }); + + $I->amOnPage('/mod/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->dontSeeLink('Create mod'); + $I->seeActionButton('Edit mod'); + $I->dontSeeActionButton('Delete mod'); + } + + public function listModsAsAuthorizedUserWithDeleteModPermission(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modList = true; + $user->getPermissions()->modDelete = true; + }); + + $I->amOnPage('/mod/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->dontSeeLink('Create mod'); + $I->dontSeeActionButton('Edit mod'); + $I->seeActionButton('Delete mod'); + } +} diff --git a/tests/functional/Web/Mod/UpdateDirectoryModCest.php b/tests/functional/Web/Mod/UpdateDirectoryModCest.php new file mode 100644 index 00000000..12871803 --- /dev/null +++ b/tests/functional/Web/Mod/UpdateDirectoryModCest.php @@ -0,0 +1,209 @@ +stopFollowingRedirects(); + $I->freezeTime('2021-01-01T00:00:00+00:00'); + } + + public function updateDirectoryModAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage(sprintf('/mod/%s/update', ArmaScriptProfilerModFixture::ID)); + + $I->seeResponseRedirectsToLogInAction(); + } + + public function updateDirectoryModAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage(sprintf('/mod/%s/update', ArmaScriptProfilerModFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + } + + public function updateDirectoryModAsAuthorizedUser(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modUpdate = true; + }); + + $I->amOnPage(sprintf('/mod/%s/update', ArmaScriptProfilerModFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeOptionIsSelected('Mod source', 'Directory'); + $I->seeInField('Mod directory', '@Arma Script Profiler'); + $I->dontSee('Mod status'); // Not visible + $I->seeInField('Mod name', 'Arma Script Profiler'); + $I->seeInField('Mod description', ''); + + // Fill form + $I->fillField('Mod directory', '@OCAP'); + $I->fillField('Mod name', 'OCAP'); + $I->fillField('Mod description', 'OCAP - AAR'); + $I->click('Apply'); + + $I->seeResponseRedirectsTo('/mod/list'); + + /** @var DirectoryMod $mod */ + $mod = $I->grabEntityFromRepository(DirectoryMod::class, ['directory' => '@OCAP']); + $I->assertSame(null, $mod->getStatus()); + $I->assertSame('OCAP', $mod->getName()); + $I->assertSame('OCAP - AAR', $mod->getDescription()); + + $I->assertSame('2020-01-01T00:00:00+00:00', $mod->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame(null, $mod->getCreatedBy()?->getId()->toString()); + $I->assertSame('2021-01-01T00:00:00+00:00', $mod->getLastUpdatedAt()?->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $mod->getLastUpdatedBy()?->getId()->toString()); + } + + public function updateDirectoryModAsAuthorizedUserWithChangeModStatusPermission(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modUpdate = true; + $user->getPermissions()->modChangeStatus = true; + }); + + $I->amOnPage(sprintf('/mod/%s/update', ArmaScriptProfilerModFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeOptionIsSelected('Mod source', 'Directory'); + $I->seeInField('Mod directory', '@Arma Script Profiler'); + $I->seeOptionIsSelected('Mod status', ''); + $I->seeInField('Mod name', 'Arma Script Profiler'); + $I->seeInField('Mod description', ''); + + // Fill form + $I->fillField('Mod directory', '@OCAP'); + $I->selectOption('Mod status', 'Deprecated'); + $I->fillField('Mod name', 'OCAP'); + $I->fillField('Mod description', 'OCAP - AAR'); + $I->click('Apply'); + + $I->seeResponseRedirectsTo('/mod/list'); + + /** @var DirectoryMod $mod */ + $mod = $I->grabEntityFromRepository(DirectoryMod::class, ['directory' => '@OCAP']); + $I->assertSame(ModStatusEnum::DEPRECATED, $mod->getStatus()); + $I->assertSame('OCAP', $mod->getName()); + $I->assertSame('OCAP - AAR', $mod->getDescription()); + + $I->assertSame('2020-01-01T00:00:00+00:00', $mod->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame(null, $mod->getCreatedBy()?->getId()->toString()); + $I->assertSame('2021-01-01T00:00:00+00:00', $mod->getLastUpdatedAt()?->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $mod->getLastUpdatedBy()?->getId()->toString()); + } + + public function updateDirectoryModAsAuthorizedUserWhenModAlreadyExists(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modUpdate = true; + }); + + $I->amOnPage(sprintf('/mod/%s/update', ArmaScriptProfilerModFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->selectOption('Mod source', 'Directory'); + $I->fillField('Mod directory', R3ModFixture::DIRECTORY); + $I->fillField('Mod name', 'R3'); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->canSeeFormErrorMessage('directory', 'Mod associated with directory "@R3" already exist.'); + } + + public function updateDirectoryModAsAuthorizedUserWithInvalidDirectoryName(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modUpdate = true; + }); + + $I->amOnPage(sprintf('/mod/%s/update', ArmaScriptProfilerModFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->selectOption('Mod source', 'Directory'); + $I->fillField('Mod directory', '@OC/AP'); + $I->fillField('Mod name', 'OCAP'); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->canSeeFormErrorMessage('directory', 'Invalid directory name.'); + } + + public function updateDirectoryModAsAuthorizedUserWithoutRequiredData(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modUpdate = true; + }); + + $I->amOnPage(sprintf('/mod/%s/update', ArmaScriptProfilerModFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->selectOption('Mod source', 'Directory'); + $I->fillField('Mod directory', ''); + $I->fillField('Mod name', ''); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->canSeeFormErrorMessage('directory', 'This value should not be blank.'); + $I->canSeeFormErrorMessage('name', 'This value should not be blank.'); + } + + public function updateDirectoryModAsAuthorizedUserWithDataTooLong(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modUpdate = true; + }); + + $I->amOnPage(sprintf('/mod/%s/update', ArmaScriptProfilerModFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->selectOption('Mod source', 'Directory'); + $I->fillField('Mod directory', '@OCAP'); + $I->fillField('Mod name', str_repeat('a', 256)); + $I->fillField('Mod description', str_repeat('a', 256)); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->canSeeFormErrorMessage('name', 'This value is too long. It should have 255 characters or less.'); + $I->canSeeFormErrorMessage('description', 'This value is too long. It should have 255 characters or less.'); + } + + public function updateDirectoryModAsAuthorizedUserWhenModDoesNotExist(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modUpdate = true; + }); + + $I->amOnPage(sprintf('/mod/%s/update', 'd2cca3c6-1c5f-4ea7-afcf-a05317a58467')); + + $I->seeResponseCodeIs(HttpCode::NOT_FOUND); + } +} diff --git a/tests/functional/Web/Mod/UpdateSteamWorkshopModCest.php b/tests/functional/Web/Mod/UpdateSteamWorkshopModCest.php new file mode 100644 index 00000000..116996ac --- /dev/null +++ b/tests/functional/Web/Mod/UpdateSteamWorkshopModCest.php @@ -0,0 +1,289 @@ +stopFollowingRedirects(); + $I->freezeTime('2021-01-01T00:00:00+00:00'); + } + + public function updateSteamWorkshopModAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage(sprintf('/mod/%s/update', ArmaForcesMedicalModFixture::ID)); + + $I->seeResponseRedirectsToLogInAction(); + } + + public function updateSteamWorkshopModAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage(sprintf('/mod/%s/update', ArmaForcesMedicalModFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + } + + public function updateSteamWorkshopModAsAuthorizedUser(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modUpdate = true; + }); + + $I->amOnPage(sprintf('/mod/%s/update', ArmaForcesMedicalModFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeOptionIsSelected('Mod source', 'Steam Workshop'); + $I->seeInField('Steam Workshop URL', 'https://steamcommunity.com/sharedfiles/filedetails/?id=1981535406'); + $I->seeOptionIsSelected('Mod type', 'Required mod'); + $I->dontSee('Mod status'); // Not visible + $I->seeInField('Mod name', 'ArmaForces - Medical'); + $I->seeInField('Mod description', ''); + + // Fill form + $I->fillField('Steam Workshop URL', 'https://steamcommunity.com/sharedfiles/filedetails/?id=1934142795'); + $I->selectOption('Mod type', 'Optional mod'); + $I->fillField('Mod name', 'AF Mods'); + $I->fillField('Mod description', 'Custom Arma 3 mods'); + $I->click('Apply'); + + $I->seeResponseRedirectsTo('/mod/list'); + + /** @var SteamWorkshopMod $mod */ + $mod = $I->grabEntityFromRepository(SteamWorkshopMod::class, ['itemId' => 1934142795]); + $I->assertSame(ModTypeEnum::OPTIONAL, $mod->getType()); + $I->assertSame(null, $mod->getStatus()); + $I->assertSame('AF Mods', $mod->getName()); + $I->assertSame('Custom Arma 3 mods', $mod->getDescription()); + + $I->assertSame('2020-01-01T00:00:00+00:00', $mod->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame(null, $mod->getCreatedBy()?->getId()->toString()); + $I->assertSame('2021-01-01T00:00:00+00:00', $mod->getLastUpdatedAt()?->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $mod->getLastUpdatedBy()?->getId()->toString()); + } + + public function updateSteamWorkshopModAsAuthorizedUserWithNameProvidedBySteamWorkshop(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modUpdate = true; + }); + + $I->amOnPage(sprintf('/mod/%s/update', ArmaForcesMedicalModFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeOptionIsSelected('Mod source', 'Steam Workshop'); + $I->seeInField('Steam Workshop URL', 'https://steamcommunity.com/sharedfiles/filedetails/?id=1981535406'); + $I->seeOptionIsSelected('Mod type', 'Required mod'); + $I->dontSee('Mod status'); // Not visible + $I->seeInField('Mod name', 'ArmaForces - Medical'); + $I->seeInField('Mod description', ''); + + // Fill form + $I->fillField('Steam Workshop URL', 'https://steamcommunity.com/sharedfiles/filedetails/?id=1934142795'); + $I->selectOption('Mod type', 'Optional mod'); + $I->fillField('Mod name', ''); + $I->fillField('Mod description', ''); + $I->click('Apply'); + + $I->seeResponseRedirectsTo('/mod/list'); + + /** @var SteamWorkshopMod $mod */ + $mod = $I->grabEntityFromRepository(SteamWorkshopMod::class, ['itemId' => 1934142795]); + $I->assertSame(ModTypeEnum::OPTIONAL, $mod->getType()); + $I->assertSame(null, $mod->getStatus()); + $I->assertSame('ArmaForces - Mods', $mod->getName()); // From Steam Workshop + $I->assertSame(null, $mod->getDescription()); + + $I->assertSame('2020-01-01T00:00:00+00:00', $mod->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame(null, $mod->getCreatedBy()?->getId()->toString()); + $I->assertSame('2021-01-01T00:00:00+00:00', $mod->getLastUpdatedAt()?->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $mod->getLastUpdatedBy()?->getId()->toString()); + } + + public function updateSteamWorkshopModAsAuthorizedUserWithChangeModStatusPermission(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modUpdate = true; + $user->getPermissions()->modChangeStatus = true; + }); + + $I->amOnPage(sprintf('/mod/%s/update', ArmaForcesMedicalModFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeOptionIsSelected('Mod source', 'Steam Workshop'); + $I->seeInField('Steam Workshop URL', 'https://steamcommunity.com/sharedfiles/filedetails/?id=1981535406'); + $I->seeOptionIsSelected('Mod type', 'Required mod'); + $I->seeOptionIsSelected('Mod status', ''); + $I->seeInField('Mod name', 'ArmaForces - Medical'); + $I->seeInField('Mod description', ''); + + // Fill form + $I->fillField('Steam Workshop URL', 'https://steamcommunity.com/sharedfiles/filedetails/?id=1934142795'); + $I->selectOption('Mod type', 'Optional mod'); + $I->selectOption('Mod status', 'Deprecated'); + $I->fillField('Mod name', 'AF Mods'); + $I->fillField('Mod description', 'Custom Arma 3 mods'); + $I->click('Apply'); + + $I->seeResponseRedirectsTo('/mod/list'); + + /** @var SteamWorkshopMod $mod */ + $mod = $I->grabEntityFromRepository(SteamWorkshopMod::class, ['itemId' => 1934142795]); + $I->assertSame(ModTypeEnum::OPTIONAL, $mod->getType()); + $I->assertSame(ModStatusEnum::DEPRECATED, $mod->getStatus()); + $I->assertSame('AF Mods', $mod->getName()); + $I->assertSame('Custom Arma 3 mods', $mod->getDescription()); + + $I->assertSame('2020-01-01T00:00:00+00:00', $mod->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame(null, $mod->getCreatedBy()?->getId()->toString()); + $I->assertSame('2021-01-01T00:00:00+00:00', $mod->getLastUpdatedAt()?->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $mod->getLastUpdatedBy()?->getId()->toString()); + } + + public function updateSteamWorkshopModAsAuthorizedUserWhenModDoesNotExistInSteamApi(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modUpdate = true; + }); + + $I->amOnPage(sprintf('/mod/%s/update', ArmaForcesMedicalModFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $url = SteamHelper::itemIdToItemUrl(9999999); + $I->fillField('Steam Workshop URL', $url); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('url', 'Mod not found.'); + } + + public function updateSteamWorkshopModAsAuthorizedUserWithInvalidModUrl(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modUpdate = true; + }); + + $I->amOnPage(sprintf('/mod/%s/update', ArmaForcesMedicalModFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Steam Workshop URL', 'https://example.com'); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('url', 'Invalid Steam Workshop mod url.'); + } + + public function updateSteamWorkshopModAsAuthorizedUserWhenModAlreadyExists(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modUpdate = true; + }); + + $I->amOnPage(sprintf('/mod/%s/update', LegacyArmaForcesModsModFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $url = SteamHelper::itemIdToItemUrl(ArmaForcesMedicalModFixture::ITEM_ID); + $I->fillField('Steam Workshop URL', $url); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $message = sprintf('Mod associated with url "%s" already exist.', $url); + $I->seeFormErrorMessage('url', $message); + } + + public function updateSteamWorkshopModAsAuthorizedUserWhenUrlIsNotAnArma3Mod(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modUpdate = true; + }); + + $I->amOnPage(sprintf('/mod/%s/update', ArmaForcesMedicalModFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $url = SteamHelper::itemIdToItemUrl(455312245); + $I->fillField('Steam Workshop URL', $url); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('url', 'Url is not an Arma 3 mod.'); + } + + public function updateSteamWorkshopModAsAuthorizedUserWithoutRequiredData(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modUpdate = true; + }); + + $I->amOnPage(sprintf('/mod/%s/update', ArmaForcesMedicalModFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Steam Workshop URL', ''); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('url', 'This value should not be blank.'); + } + + public function updateSteamWorkshopModAsAuthorizedUserWithDataTooLong(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modUpdate = true; + }); + + $I->amOnPage(sprintf('/mod/%s/update', ArmaForcesMedicalModFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Steam Workshop URL', 'https://steamcommunity.com/sharedfiles/filedetails/?id=1934142795'); + $I->fillField('Mod name', str_repeat('a', 256)); + $I->fillField('Mod description', str_repeat('a', 256)); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'This value is too long. It should have 255 characters or less.'); + $I->seeFormErrorMessage('description', 'This value is too long. It should have 255 characters or less.'); + } + + public function updateSteamWorkshopModAsAuthorizedUserWhenModDoesNotExist(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modUpdate = true; + }); + + $I->amOnPage(sprintf('/mod/%s/update', 'd2cca3c6-1c5f-4ea7-afcf-a05317a58467')); + + $I->seeResponseCodeIs(HttpCode::NOT_FOUND); + } +} From 403514f76772e59d943c391e21a04788e46d244b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Skowro=C5=84ski?= Date: Wed, 10 Jan 2024 22:53:07 +0100 Subject: [PATCH 13/17] Add mod group tests --- .../Web/ModGroup/CreateModGroupCest.php | 134 +++++++++++++++ .../Web/ModGroup/DeleteModGroupCest.php | 64 +++++++ .../Web/ModGroup/ListModGroupsCest.php | 97 +++++++++++ .../Web/ModGroup/UpdateModGroupCest.php | 156 ++++++++++++++++++ 4 files changed, 451 insertions(+) create mode 100644 tests/functional/Web/ModGroup/CreateModGroupCest.php create mode 100644 tests/functional/Web/ModGroup/DeleteModGroupCest.php create mode 100644 tests/functional/Web/ModGroup/ListModGroupsCest.php create mode 100644 tests/functional/Web/ModGroup/UpdateModGroupCest.php diff --git a/tests/functional/Web/ModGroup/CreateModGroupCest.php b/tests/functional/Web/ModGroup/CreateModGroupCest.php new file mode 100644 index 00000000..a8af72a1 --- /dev/null +++ b/tests/functional/Web/ModGroup/CreateModGroupCest.php @@ -0,0 +1,134 @@ +stopFollowingRedirects(); + $I->freezeTime('2020-01-01T00:00:00+00:00'); + } + + public function createModGroupAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage('/mod-group/create'); + + $I->seeResponseRedirectsToLogInAction(); + } + + public function createModGroupAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage('/mod-group/create'); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + } + + public function createModGroupAsAuthorizedUser(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modGroupCreate = true; + }); + + $I->amOnPage('/mod-group/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeInField('Mod group name', ''); + $I->seeInField('Mod group description', ''); + $I->seeTableRowCheckboxesAreUnchecked('mod_group_form_mods_'); // All checkboxes are unchecked + + // Fill form + $I->fillField('Mod group name', 'CUP Terrains'); + $I->fillField('Mod group description', 'Terrains for CUP'); + $I->checkTableRowCheckbox(CupTerrainsCoreModFixture::ID); + $I->checkTableRowCheckbox(CupTerrainsMapsModFixture::ID); + $I->click('Create mod group'); + + $I->seeResponseRedirectsTo('/mod-group/list'); + + /** @var ModGroup $modGroup */ + $modGroup = $I->grabEntityFromRepository(ModGroup::class, ['name' => 'CUP Terrains']); + $I->assertSame('CUP Terrains', $modGroup->getName()); + $I->assertSame('Terrains for CUP', $modGroup->getDescription()); + $I->assertSame([ + CupTerrainsCoreModFixture::ID, + CupTerrainsMapsModFixture::ID, + ], array_map(fn (AbstractMod $mod) => $mod->getId()->toString(), $modGroup->getMods())); + + $I->assertSame('2020-01-01T00:00:00+00:00', $modGroup->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $modGroup->getCreatedBy()?->getId()->toString()); + $I->assertSame(null, $modGroup->getLastUpdatedAt()); + $I->assertSame(null, $modGroup->getLastUpdatedBy()?->getId()->toString()); + } + + public function createModGroupAsAuthorizedUserWhenModGroupAlreadyExists(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modGroupCreate = true; + }); + + $I->amOnPage('/mod-group/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Mod group name', 'CUP'); + $I->click('Create mod group'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'Mod group with the same name "CUP" already exist.'); + } + + public function createModGroupAsAuthorizedUserWithoutRequiredData(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modGroupCreate = true; + }); + + $I->amOnPage('/mod-group/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Mod group name', ''); + $I->click('Create mod group'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'This value should not be blank.'); + } + + public function createModGroupAsAuthorizedUserWithDataTooLong(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modGroupCreate = true; + }); + + $I->amOnPage('/mod-group/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Mod group name', str_repeat('a', 256)); + $I->fillField('Mod group description', str_repeat('a', 256)); + $I->click('Create mod group'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'This value is too long. It should have 255 characters or less.'); + $I->seeFormErrorMessage('description', 'This value is too long. It should have 255 characters or less.'); + } +} diff --git a/tests/functional/Web/ModGroup/DeleteModGroupCest.php b/tests/functional/Web/ModGroup/DeleteModGroupCest.php new file mode 100644 index 00000000..1adc4938 --- /dev/null +++ b/tests/functional/Web/ModGroup/DeleteModGroupCest.php @@ -0,0 +1,64 @@ +stopFollowingRedirects(); + } + + public function deleteModGroupAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage(sprintf('/mod-group/%s/delete', CupModGroupFixture::NAME)); + + $I->seeResponseRedirectsToLogInAction(); + + $I->seeInRepository(ModGroup::class, ['name' => CupModGroupFixture::NAME]); + } + + public function deleteModGroupAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage(sprintf('/mod-group/%s/delete', CupModGroupFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + + $I->seeInRepository(ModGroup::class, ['name' => CupModGroupFixture::NAME]); + } + + public function deleteModGroupAsAuthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modGroupDelete = true; + }); + + $I->amOnPage(sprintf('/mod-group/%s/delete', CupModGroupFixture::NAME)); + + $I->seeResponseRedirectsTo('/mod-group/list'); + + $I->dontSeeInRepository(ModGroup::class, ['name' => CupModGroupFixture::NAME]); + } + + public function deleteModGroupAsAuthorizedUserWhenModGroupDoesNotExist(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modGroupDelete = true; + }); + + $I->amOnPage(sprintf('/mod-group/%s/delete', 'non existing')); + + $I->seeResponseCodeIs(HttpCode::NOT_FOUND); + } +} diff --git a/tests/functional/Web/ModGroup/ListModGroupsCest.php b/tests/functional/Web/ModGroup/ListModGroupsCest.php new file mode 100644 index 00000000..15bbf8ed --- /dev/null +++ b/tests/functional/Web/ModGroup/ListModGroupsCest.php @@ -0,0 +1,97 @@ +stopFollowingRedirects(); + } + + public function listModGroupsAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage('/mod-group/list'); + + $I->seeResponseRedirectsToLogInAction(); + } + + public function listModGroupsAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage('/mod-group/list'); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + } + + public function listModGroupsAsAuthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modGroupList = true; + }); + + $I->amOnPage('/mod-group/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->dontSeeLink('Create mod group'); + $I->dontSeeActionButton('Edit mod group'); + $I->dontSeeActionButton('Delete mod group'); + } + + public function listModGroupsAsAuthorizedUserWithCreateModPermission(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modGroupList = true; + $user->getPermissions()->modGroupCreate = true; + }); + + $I->amOnPage('/mod-group/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeLink('Create mod group'); + $I->dontSeeActionButton('Edit mod group'); + $I->dontSeeActionButton('Delete mod group'); + } + + public function listModGroupsAsAuthorizedUserWithUpdateModPermission(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modGroupList = true; + $user->getPermissions()->modGroupUpdate = true; + }); + + $I->amOnPage('/mod-group/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->dontSeeLink('Create mod group'); + $I->seeActionButton('Edit mod group'); + $I->dontSeeActionButton('Delete mod group'); + } + + public function listModGroupsAsAuthorizedUserWithDeleteModPermission(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modGroupList = true; + $user->getPermissions()->modGroupDelete = true; + }); + + $I->amOnPage('/mod-group/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->dontSeeLink('Create mod group'); + $I->dontSeeActionButton('Edit mod group'); + $I->seeActionButton('Delete mod group'); + } +} diff --git a/tests/functional/Web/ModGroup/UpdateModGroupCest.php b/tests/functional/Web/ModGroup/UpdateModGroupCest.php new file mode 100644 index 00000000..bc37bf9d --- /dev/null +++ b/tests/functional/Web/ModGroup/UpdateModGroupCest.php @@ -0,0 +1,156 @@ +stopFollowingRedirects(); + $I->freezeTime('2021-01-01T00:00:00+00:00'); + } + + public function updateModGroupAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage(sprintf('/mod-group/%s/update', RhsModGroupFixture::NAME)); + + $I->seeResponseRedirectsToLogInAction(); + } + + public function updateModGroupAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage(sprintf('/mod-group/%s/update', RhsModGroupFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + } + + public function updateModGroupAsAuthorizedUser(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modGroupUpdate = true; + }); + + $I->amOnPage(sprintf('/mod-group/%s/update', RhsModGroupFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeInField('Mod group name', 'RHS'); + $I->seeInField('Mod group description', ''); + $I->seeTableRowCheckboxesAreUnchecked('mod_group_form_mods_', [ + RhsAfrfModFixture::ID, + RhsGrefModFixture::ID, + RhsUsafModFixture::ID, + ]); // Some checkboxes checked + + // Fill form + $I->fillField('Mod group name', 'CUP Terrains'); + $I->fillField('Mod group description', 'Terrains for CUP'); + $I->uncheckTableRowCheckbox(RhsAfrfModFixture::ID); + $I->uncheckTableRowCheckbox(RhsGrefModFixture::ID); + $I->uncheckTableRowCheckbox(RhsUsafModFixture::ID); + $I->checkTableRowCheckbox(CupTerrainsCoreModFixture::ID); + $I->checkTableRowCheckbox(CupTerrainsMapsModFixture::ID); + $I->click('Apply'); + + $I->seeResponseRedirectsTo('/mod-group/list'); + + /** @var ModGroup $modGroup */ + $modGroup = $I->grabEntityFromRepository(ModGroup::class, ['name' => 'CUP Terrains']); + $I->assertSame('CUP Terrains', $modGroup->getName()); + $I->assertSame('Terrains for CUP', $modGroup->getDescription()); + $I->assertSame([ + CupTerrainsCoreModFixture::ID, + CupTerrainsMapsModFixture::ID, + ], array_map(fn (AbstractMod $mod) => $mod->getId()->toString(), $modGroup->getMods())); + + $I->assertSame('2020-01-01T00:00:00+00:00', $modGroup->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame(null, $modGroup->getCreatedBy()?->getId()->toString()); + $I->assertSame('2021-01-01T00:00:00+00:00', $modGroup->getLastUpdatedAt()?->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $modGroup->getLastUpdatedBy()?->getId()->toString()); + } + + public function updateModGroupAsAuthorizedUserWhenModGroupAlreadyExists(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modGroupUpdate = true; + }); + + $I->amOnPage(sprintf('/mod-group/%s/update', RhsModGroupFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Mod group name', 'CUP'); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'Mod group with the same name "CUP" already exist.'); + } + + public function updateModGroupAsAuthorizedUserWithoutRequiredData(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modGroupUpdate = true; + }); + + $I->amOnPage(sprintf('/mod-group/%s/update', RhsModGroupFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Mod group name', ''); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'This value should not be blank.'); + } + + public function updateModGroupAsAuthorizedUserWithDataTooLong(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modGroupUpdate = true; + }); + + $I->amOnPage(sprintf('/mod-group/%s/update', RhsModGroupFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Mod group name', str_repeat('a', 256)); + $I->fillField('Mod group description', str_repeat('a', 256)); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'This value is too long. It should have 255 characters or less.'); + $I->seeFormErrorMessage('description', 'This value is too long. It should have 255 characters or less.'); + } + + public function updateModGroupAsAuthorizedUserWhenModGroupDoesNotExist(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modGroupUpdate = true; + }); + + $I->amOnPage(sprintf('/mod-group/%s/update', 'non existing')); + + $I->seeResponseCodeIs(HttpCode::NOT_FOUND); + } +} From 885ebee59b3a313d2cf155b602b98dd757195dfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Skowro=C5=84ski?= Date: Wed, 10 Jan 2024 22:53:15 +0100 Subject: [PATCH 14/17] Add mod list tests --- .../Web/ModList/CopyModListCest.php | 346 +++++++++++++++++ .../Web/ModList/CreateModListCest.php | 266 ++++++++++++++ .../Web/ModList/DeleteModListCest.php | 78 ++++ .../Web/ModList/ListModListsCest.php | 140 +++++++ .../Web/ModList/UpdateModListCest.php | 347 ++++++++++++++++++ 5 files changed, 1177 insertions(+) create mode 100644 tests/functional/Web/ModList/CopyModListCest.php create mode 100644 tests/functional/Web/ModList/CreateModListCest.php create mode 100644 tests/functional/Web/ModList/DeleteModListCest.php create mode 100644 tests/functional/Web/ModList/ListModListsCest.php create mode 100644 tests/functional/Web/ModList/UpdateModListCest.php diff --git a/tests/functional/Web/ModList/CopyModListCest.php b/tests/functional/Web/ModList/CopyModListCest.php new file mode 100644 index 00000000..8652540f --- /dev/null +++ b/tests/functional/Web/ModList/CopyModListCest.php @@ -0,0 +1,346 @@ +stopFollowingRedirects(); + $I->freezeTime('2020-01-01T00:00:00+00:00'); + } + + public function copyModListAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage(sprintf('/mod-list/%s/copy', RhsModListFixture::NAME)); + + $I->seeResponseRedirectsToLogInAction(); + } + + public function copyModListAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage(sprintf('/mod-list/%s/copy', RhsModListFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + } + + public function copyModListAsAuthorizedUser(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modListCopy = true; + }); + + $I->amOnPage(sprintf('/mod-list/%s/copy', RhsModListFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeInField('Mod list name', 'RHS'); + $I->seeInField('Mod list description', ''); + $I->dontSee('Mod list owner'); + $I->dontSeeCheckboxIsChecked('Mod list active'); + $I->dontSee('Mod list approved'); + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_modGroups_', [ + RhsModGroupFixture::ID, + ]); // Same as the source mod list + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_dlcs_', [ + CslaIronCurtainDlcFixture::ID, + ]); // Same as the source mod list + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_mods_', [ + R3ModFixture::ID, + ArmaScriptProfilerModFixture::ID, + + AceInteractionMenuExpansionModFixture::ID, + ArmaForcesAceMedicalModFixture::ID, + LegacyArmaForcesModsModFixture::ID, + ArmaForcesJbadBuildingFixModFixture::ID, + ArmaForcesMedicalModFixture::ID, + ]); // Same as the source mod list + + // Fill form + $I->fillField('Mod list name', 'Custom'); + $I->fillField('Mod list description', 'Custom modlist'); + $I->checkOption('Mod list active'); + $I->uncheckTableRowCheckbox(RhsModGroupFixture::ID); // Mod group + $I->checkTableRowCheckbox(CupModGroupFixture::ID); // Mod group + $I->uncheckTableRowCheckbox(CslaIronCurtainDlcFixture::ID); // DLC + $I->checkTableRowCheckbox(SogPrairieFireDlcFixture::ID); // DLC + $I->uncheckTableRowCheckbox(R3ModFixture::ID); // Mod + $I->uncheckTableRowCheckbox(ArmaScriptProfilerModFixture::ID); // Mod + $I->click('Create mod list'); + + $I->seeResponseRedirectsTo('/mod-list/list'); + + /** @var ModList $modList */ + $modList = $I->grabEntityFromRepository(ModList::class, ['name' => 'Custom']); + $I->assertSame('Custom', $modList->getName()); + $I->assertSame('Custom modlist', $modList->getDescription()); + $I->assertSame(User1Fixture::ID, $modList->getOwner()->getId()->toString()); // Current user + $I->assertSame(true, $modList->isActive()); + $I->assertSame(false, $modList->isApproved()); + $I->assertSame([ + CupModGroupFixture::ID, + ], array_map(fn (ModGroup $modGroup) => $modGroup->getId()->toString(), $modList->getModGroups())); + $I->assertSame([ + SogPrairieFireDlcFixture::ID, + ], array_map(fn (Dlc $dlc) => $dlc->getId()->toString(), $modList->getDlcs())); + $I->assertSame([ + AceInteractionMenuExpansionModFixture::ID, + ArmaForcesAceMedicalModFixture::ID, + LegacyArmaForcesModsModFixture::ID, + ArmaForcesJbadBuildingFixModFixture::ID, + ArmaForcesMedicalModFixture::ID, + ], array_map(fn (AbstractMod $mod) => $mod->getId()->toString(), $modList->getMods())); + + $I->assertSame('2020-01-01T00:00:00+00:00', $modList->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $modList->getCreatedBy()?->getId()->toString()); + $I->assertSame(null, $modList->getLastUpdatedAt()?->format(DATE_ATOM)); + $I->assertSame(null, $modList->getLastUpdatedBy()?->getId()->toString()); + } + + public function copyModListAsAuthorizedUserWithModListApprovePermission(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modListCopy = true; + $user->getPermissions()->modListApprove = true; + }); + + $I->amOnPage(sprintf('/mod-list/%s/copy', RhsModListFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeInField('Mod list name', 'RHS'); + $I->seeInField('Mod list description', ''); + $I->dontSee('Mod list owner'); + $I->dontSeeCheckboxIsChecked('Mod list active'); + $I->dontSeeCheckboxIsChecked('Mod list approved'); + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_modGroups_', [ + RhsModGroupFixture::ID, + ]); // Same as the source mod list + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_dlcs_', [ + CslaIronCurtainDlcFixture::ID, + ]); // Same as the source mod list + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_mods_', [ + R3ModFixture::ID, + ArmaScriptProfilerModFixture::ID, + + AceInteractionMenuExpansionModFixture::ID, + ArmaForcesAceMedicalModFixture::ID, + LegacyArmaForcesModsModFixture::ID, + ArmaForcesJbadBuildingFixModFixture::ID, + ArmaForcesMedicalModFixture::ID, + ]); // Same as the source mod list + + // Fill form + $I->fillField('Mod list name', 'Custom'); + $I->fillField('Mod list description', 'Custom modlist'); + $I->checkOption('Mod list active'); + $I->checkOption('Mod list approved'); + $I->uncheckTableRowCheckbox(RhsModGroupFixture::ID); // Mod group + $I->checkTableRowCheckbox(CupModGroupFixture::ID); // Mod group + $I->uncheckTableRowCheckbox(CslaIronCurtainDlcFixture::ID); // DLC + $I->checkTableRowCheckbox(SogPrairieFireDlcFixture::ID); // DLC + $I->uncheckTableRowCheckbox(R3ModFixture::ID); // Mod + $I->uncheckTableRowCheckbox(ArmaScriptProfilerModFixture::ID); // Mod + $I->click('Create mod list'); + + $I->seeResponseRedirectsTo('/mod-list/list'); + + /** @var ModList $modList */ + $modList = $I->grabEntityFromRepository(ModList::class, ['name' => 'Custom']); + $I->assertSame('Custom', $modList->getName()); + $I->assertSame('Custom modlist', $modList->getDescription()); + $I->assertSame(User1Fixture::ID, $modList->getOwner()->getId()->toString()); // Current user + $I->assertSame(true, $modList->isActive()); + $I->assertSame(true, $modList->isApproved()); + $I->assertSame([ + CupModGroupFixture::ID, + ], array_map(fn (ModGroup $modGroup) => $modGroup->getId()->toString(), $modList->getModGroups())); + $I->assertSame([ + SogPrairieFireDlcFixture::ID, + ], array_map(fn (Dlc $dlc) => $dlc->getId()->toString(), $modList->getDlcs())); + $I->assertSame([ + AceInteractionMenuExpansionModFixture::ID, + ArmaForcesAceMedicalModFixture::ID, + LegacyArmaForcesModsModFixture::ID, + ArmaForcesJbadBuildingFixModFixture::ID, + ArmaForcesMedicalModFixture::ID, + ], array_map(fn (AbstractMod $mod) => $mod->getId()->toString(), $modList->getMods())); + + $I->assertSame('2020-01-01T00:00:00+00:00', $modList->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $modList->getCreatedBy()?->getId()->toString()); + $I->assertSame(null, $modList->getLastUpdatedAt()?->format(DATE_ATOM)); + $I->assertSame(null, $modList->getLastUpdatedBy()?->getId()->toString()); + } + + public function copyModListAsAuthorizedUserWithModListUpdatePermission(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modListCopy = true; + $user->getPermissions()->modListUpdate = true; + }); + + $I->amOnPage(sprintf('/mod-list/%s/copy', RhsModListFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeInField('Mod list name', 'RHS'); + $I->seeInField('Mod list description', ''); + $I->seeOptionIsSelected('Mod list owner', User1Fixture::USERNAME); // Current user + $I->dontSeeCheckboxIsChecked('Mod list active'); + $I->dontSee('Mod list approved'); + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_modGroups_', [ + RhsModGroupFixture::ID, + ]); // Same as the source mod list + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_dlcs_', [ + CslaIronCurtainDlcFixture::ID, + ]); // Same as the source mod list + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_mods_', [ + R3ModFixture::ID, + ArmaScriptProfilerModFixture::ID, + + AceInteractionMenuExpansionModFixture::ID, + ArmaForcesAceMedicalModFixture::ID, + LegacyArmaForcesModsModFixture::ID, + ArmaForcesJbadBuildingFixModFixture::ID, + ArmaForcesMedicalModFixture::ID, + ]); // Same as the source mod list + + // Fill form + $I->fillField('Mod list name', 'Custom'); + $I->fillField('Mod list description', 'Custom modlist'); + $I->selectOption('Mod list owner', User3Fixture::USERNAME); + $I->checkOption('Mod list active'); + $I->uncheckTableRowCheckbox(RhsModGroupFixture::ID); // Mod group + $I->checkTableRowCheckbox(CupModGroupFixture::ID); // Mod group + $I->uncheckTableRowCheckbox(CslaIronCurtainDlcFixture::ID); // DLC + $I->checkTableRowCheckbox(SogPrairieFireDlcFixture::ID); // DLC + $I->uncheckTableRowCheckbox(R3ModFixture::ID); // Mod + $I->uncheckTableRowCheckbox(ArmaScriptProfilerModFixture::ID); // Mod + $I->click('Create mod list'); + + $I->seeResponseRedirectsTo('/mod-list/list'); + + /** @var ModList $modList */ + $modList = $I->grabEntityFromRepository(ModList::class, ['name' => 'Custom']); + $I->assertSame('Custom', $modList->getName()); + $I->assertSame('Custom modlist', $modList->getDescription()); + $I->assertSame(User3Fixture::ID, $modList->getOwner()->getId()->toString()); + $I->assertSame(true, $modList->isActive()); + $I->assertSame(false, $modList->isApproved()); + $I->assertSame([ + CupModGroupFixture::ID, + ], array_map(fn (ModGroup $modGroup) => $modGroup->getId()->toString(), $modList->getModGroups())); + $I->assertSame([ + SogPrairieFireDlcFixture::ID, + ], array_map(fn (Dlc $dlc) => $dlc->getId()->toString(), $modList->getDlcs())); + $I->assertSame([ + AceInteractionMenuExpansionModFixture::ID, + ArmaForcesAceMedicalModFixture::ID, + LegacyArmaForcesModsModFixture::ID, + ArmaForcesJbadBuildingFixModFixture::ID, + ArmaForcesMedicalModFixture::ID, + ], array_map(fn (AbstractMod $mod) => $mod->getId()->toString(), $modList->getMods())); + + $I->assertSame('2020-01-01T00:00:00+00:00', $modList->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $modList->getCreatedBy()?->getId()->toString()); + $I->assertSame(null, $modList->getLastUpdatedAt()?->format(DATE_ATOM)); + $I->assertSame(null, $modList->getLastUpdatedBy()?->getId()->toString()); + } + + public function copyModListAsAuthorizedUserWhenModListAlreadyExists(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modListCopy = true; + }); + + $I->amOnPage(sprintf('/mod-list/%s/copy', RhsModListFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Mod list name', DefaultModListFixture::NAME); + $I->click('Create mod list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'Mod list with the same name "Default" already exist.'); + } + + public function copyModListAsAuthorizedUserWithoutRequiredData(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modListCopy = true; + }); + + $I->amOnPage(sprintf('/mod-list/%s/copy', RhsModListFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Mod list name', ''); + $I->click('Create mod list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'This value should not be blank.'); + } + + public function copyModListAsAuthorizedUserWithDataTooLong(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modListCopy = true; + }); + + $I->amOnPage(sprintf('/mod-list/%s/copy', RhsModListFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Mod list name', str_repeat('a', 256)); + $I->fillField('Mod list description', str_repeat('a', 256)); + $I->click('Create mod list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'This value is too long. It should have 255 characters or less.'); + $I->seeFormErrorMessage('description', 'This value is too long. It should have 255 characters or less.'); + } + + public function copyModListAsAuthorizedUserWhenModListDoesNotExist(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modListCopy = true; + }); + + $I->amOnPage(sprintf('/mod-list/%s/copy', 'non existing')); + + $I->seeResponseCodeIs(HttpCode::NOT_FOUND); + } +} diff --git a/tests/functional/Web/ModList/CreateModListCest.php b/tests/functional/Web/ModList/CreateModListCest.php new file mode 100644 index 00000000..95bfe8f4 --- /dev/null +++ b/tests/functional/Web/ModList/CreateModListCest.php @@ -0,0 +1,266 @@ +stopFollowingRedirects(); + $I->freezeTime('2020-01-01T00:00:00+00:00'); + } + + public function createModListAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage('/mod-list/create'); + + $I->seeResponseRedirectsToLogInAction(); + } + + public function createModListAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage('/mod-list/create'); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + } + + public function createModListAsAuthorizedUser(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modListCreate = true; + }); + + $I->amOnPage('/mod-list/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeInField('Mod list name', ''); + $I->seeInField('Mod list description', ''); + $I->dontSee('Mod list owner'); + $I->seeCheckboxIsChecked('Mod list active'); + $I->dontSee('Mod list approved'); + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_modGroups_'); // All mod group checkboxes are unchecked + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_dlcs_'); // All DLC checkboxes are unchecked + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_mods_'); // All mod checkboxes are unchecked + + // Fill form + $I->fillField('Mod list name', 'Custom'); + $I->fillField('Mod list description', 'Custom modlist'); + $I->uncheckOption('Mod list active'); + $I->checkTableRowCheckbox(CupModGroupFixture::ID); // Mod group + $I->checkTableRowCheckbox(CslaIronCurtainDlcFixture::ID); // DLC + $I->checkTableRowCheckbox(RhsAfrfModFixture::ID); // Mod + $I->click('Create mod list'); + + $I->seeResponseRedirectsTo('/mod-list/list'); + + /** @var ModList $modList */ + $modList = $I->grabEntityFromRepository(ModList::class, ['name' => 'Custom']); + $I->assertSame('Custom', $modList->getName()); + $I->assertSame('Custom modlist', $modList->getDescription()); + $I->assertSame(User1Fixture::ID, $modList->getOwner()->getId()->toString()); // Current user + $I->assertSame(false, $modList->isActive()); + $I->assertSame(false, $modList->isApproved()); + $I->assertSame([ + CupModGroupFixture::ID, + ], array_map(fn (ModGroup $modGroup) => $modGroup->getId()->toString(), $modList->getModGroups())); + $I->assertSame([ + CslaIronCurtainDlcFixture::ID, + ], array_map(fn (Dlc $dlc) => $dlc->getId()->toString(), $modList->getDlcs())); + $I->assertSame([ + RhsAfrfModFixture::ID, + ], array_map(fn (AbstractMod $mod) => $mod->getId()->toString(), $modList->getMods())); + + $I->assertSame('2020-01-01T00:00:00+00:00', $modList->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $modList->getCreatedBy()?->getId()->toString()); + $I->assertSame(null, $modList->getLastUpdatedAt()); + $I->assertSame(null, $modList->getLastUpdatedBy()?->getId()->toString()); + } + + public function createModListAsAuthorizedUserWithModListUpdatePermission(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modListCreate = true; + $user->getPermissions()->modListUpdate = true; + }); + + $I->amOnPage('/mod-list/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeInField('Mod list name', ''); + $I->seeInField('Mod list description', ''); + $I->seeOptionIsSelected('Mod list owner', User1Fixture::USERNAME); + $I->seeCheckboxIsChecked('Mod list active'); + $I->dontSee('Mod list approved'); + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_modGroups_'); // All mod group checkboxes are unchecked + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_dlcs_'); // All DLC checkboxes are unchecked + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_mods_'); // All mod checkboxes are unchecked + + // Fill form + $I->fillField('Mod list name', 'Custom'); + $I->fillField('Mod list description', 'Custom modlist'); + $I->selectOption('Mod list owner', User2Fixture::USERNAME); + $I->uncheckOption('Mod list active'); + $I->checkTableRowCheckbox(CupModGroupFixture::ID); // Mod group + $I->checkTableRowCheckbox(CslaIronCurtainDlcFixture::ID); // DLC + $I->checkTableRowCheckbox(RhsAfrfModFixture::ID); // Mod + $I->click('Create mod list'); + + $I->seeResponseRedirectsTo('/mod-list/list'); + + /** @var ModList $modList */ + $modList = $I->grabEntityFromRepository(ModList::class, ['name' => 'Custom']); + $I->assertSame('Custom', $modList->getName()); + $I->assertSame('Custom modlist', $modList->getDescription()); + $I->assertSame(User2Fixture::ID, $modList->getOwner()->getId()->toString()); // Current user + $I->assertSame(false, $modList->isActive()); + $I->assertSame(false, $modList->isApproved()); + $I->assertSame([ + CupModGroupFixture::ID, + ], array_map(fn (ModGroup $modGroup) => $modGroup->getId()->toString(), $modList->getModGroups())); + $I->assertSame([ + CslaIronCurtainDlcFixture::ID, + ], array_map(fn (Dlc $dlc) => $dlc->getId()->toString(), $modList->getDlcs())); + $I->assertSame([ + RhsAfrfModFixture::ID, + ], array_map(fn (AbstractMod $mod) => $mod->getId()->toString(), $modList->getMods())); + + $I->assertSame('2020-01-01T00:00:00+00:00', $modList->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $modList->getCreatedBy()?->getId()->toString()); + $I->assertSame(null, $modList->getLastUpdatedAt()); + $I->assertSame(null, $modList->getLastUpdatedBy()?->getId()->toString()); + } + + public function createModListAsAuthorizedUserWithModListApprovePermission(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modListCreate = true; + $user->getPermissions()->modListApprove = true; + }); + + $I->amOnPage('/mod-list/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeInField('Mod list name', ''); + $I->seeInField('Mod list description', ''); + $I->dontSee('Mod list owner'); + $I->seeCheckboxIsChecked('Mod list active'); + $I->dontSeeCheckboxIsChecked('Mod list approved'); + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_modGroups_'); // All mod group checkboxes are unchecked + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_dlcs_'); // All DLC checkboxes are unchecked + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_mods_'); // All mod checkboxes are unchecked + + // Fill form + $I->fillField('Mod list name', 'Custom'); + $I->fillField('Mod list description', 'Custom modlist'); + $I->uncheckOption('Mod list active'); + $I->checkOption('Mod list approved'); + $I->checkTableRowCheckbox(CupModGroupFixture::ID); // Mod group + $I->checkTableRowCheckbox(CslaIronCurtainDlcFixture::ID); // DLC + $I->checkTableRowCheckbox(RhsAfrfModFixture::ID); // Mod + $I->click('Create mod list'); + + $I->seeResponseRedirectsTo('/mod-list/list'); + + /** @var ModList $modList */ + $modList = $I->grabEntityFromRepository(ModList::class, ['name' => 'Custom']); + $I->assertSame('Custom', $modList->getName()); + $I->assertSame('Custom modlist', $modList->getDescription()); + $I->assertSame(User1Fixture::ID, $modList->getOwner()->getId()->toString()); // Current user + $I->assertSame(false, $modList->isActive()); + $I->assertSame(true, $modList->isApproved()); + $I->assertSame([ + CupModGroupFixture::ID, + ], array_map(fn (ModGroup $modGroup) => $modGroup->getId()->toString(), $modList->getModGroups())); + $I->assertSame([ + CslaIronCurtainDlcFixture::ID, + ], array_map(fn (Dlc $dlc) => $dlc->getId()->toString(), $modList->getDlcs())); + $I->assertSame([ + RhsAfrfModFixture::ID, + ], array_map(fn (AbstractMod $mod) => $mod->getId()->toString(), $modList->getMods())); + + $I->assertSame('2020-01-01T00:00:00+00:00', $modList->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $modList->getCreatedBy()?->getId()->toString()); + $I->assertSame(null, $modList->getLastUpdatedAt()); + $I->assertSame(null, $modList->getLastUpdatedBy()?->getId()->toString()); + } + + public function createModListAsAuthorizedUserWhenModListAlreadyExists(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modListCreate = true; + }); + + $I->amOnPage('/mod-list/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Mod list name', DefaultModListFixture::NAME); + $I->click('Create mod list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'Mod list with the same name "Default" already exist.'); + } + + public function createModListAsAuthorizedUserWithoutRequiredData(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modListCreate = true; + }); + + $I->amOnPage('/mod-list/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Mod list name', ''); + $I->click('Create mod list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'This value should not be blank.'); + } + + public function createModListAsAuthorizedUserWithDataTooLong(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modListCreate = true; + }); + + $I->amOnPage('/mod-list/create'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Mod list name', str_repeat('a', 256)); + $I->fillField('Mod list description', str_repeat('a', 256)); + $I->click('Create mod list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'This value is too long. It should have 255 characters or less.'); + $I->seeFormErrorMessage('description', 'This value is too long. It should have 255 characters or less.'); + } +} diff --git a/tests/functional/Web/ModList/DeleteModListCest.php b/tests/functional/Web/ModList/DeleteModListCest.php new file mode 100644 index 00000000..66890fd4 --- /dev/null +++ b/tests/functional/Web/ModList/DeleteModListCest.php @@ -0,0 +1,78 @@ +stopFollowingRedirects(); + } + + public function deleteModListAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage(sprintf('/mod-list/%s/delete', DefaultModListFixture::NAME)); + + $I->seeResponseRedirectsToLogInAction(); + + $I->seeInRepository(ModList::class, ['name' => DefaultModListFixture::NAME]); + } + + public function deleteModListAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage(sprintf('/mod-list/%s/delete', DefaultModListFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + + $I->seeInRepository(ModList::class, ['name' => DefaultModListFixture::NAME]); + } + + public function deleteModListAsAuthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modListDelete = true; + }); + + $I->amOnPage(sprintf('/mod-list/%s/delete', DefaultModListFixture::NAME)); + + $I->seeResponseRedirectsTo('/mod-list/list'); + + $I->dontSeeInRepository(ModList::class, ['name' => DefaultModListFixture::NAME]); + } + + public function deleteModListAsModListOwner(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(CupModListFixture::OWNER_ID, function (User $user): void { + $user->getPermissions()->modListDelete = false; + }); + + $I->amOnPage(sprintf('/mod-list/%s/delete', CupModListFixture::NAME)); + + $I->seeResponseRedirectsTo('/mod-list/list'); + + $I->dontSeeInRepository(ModList::class, ['name' => CupModListFixture::NAME]); + } + + public function deleteModListAsAuthorizedUserWhenModListDoesNotExist(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modListDelete = true; + }); + + $I->amOnPage(sprintf('/mod-list/%s/delete', 'non existing')); + + $I->seeResponseCodeIs(HttpCode::NOT_FOUND); + } +} diff --git a/tests/functional/Web/ModList/ListModListsCest.php b/tests/functional/Web/ModList/ListModListsCest.php new file mode 100644 index 00000000..a19fca96 --- /dev/null +++ b/tests/functional/Web/ModList/ListModListsCest.php @@ -0,0 +1,140 @@ +stopFollowingRedirects(); + } + + public function listModListsAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage('/mod-list/list'); + $I->seeResponseRedirectsToLogInAction(); + } + + public function listModListsAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User3Fixture::ID); + + $I->amOnPage('/mod-list/list'); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + } + + public function listModListsAsAuthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User3Fixture::ID, function (User $user): void { + $user->getPermissions()->modListList = true; + }); + + $I->amOnPage('/mod-list/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->dontSeeLink('Create mod list'); + $I->seeActionButton('Download mod list'); + $I->dontSeeActionButton('Edit mod list'); + $I->dontSeeActionButton('Copy and edit mod list'); + $I->dontSeeActionButton('Delete mod list'); + } + + public function listModListsAsAuthorizedUserWithCreateModListPermission(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User3Fixture::ID, function (User $user): void { + $user->getPermissions()->modListList = true; + $user->getPermissions()->modListCreate = true; + }); + + $I->amOnPage('/mod-list/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeLink('Create mod list'); + $I->seeActionButton('Download mod list'); + $I->dontSeeActionButton('Edit mod list'); + $I->dontSeeActionButton('Copy and edit mod list'); + $I->dontSeeActionButton('Delete mod list'); + } + + public function listModListsAsAuthorizedUserWithUpdateModListPermission(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User3Fixture::ID, function (User $user): void { + $user->getPermissions()->modListList = true; + $user->getPermissions()->modListUpdate = true; + }); + + $I->amOnPage('/mod-list/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->dontSeeLink('Create mod list'); + $I->seeActionButton('Download mod list'); + $I->seeActionButton('Edit mod list'); + $I->dontSeeActionButton('Copy and edit mod list'); + $I->dontSeeActionButton('Delete mod list'); + } + + public function listModListsAsAuthorizedUserWithModListOwnership(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(CupModListFixture::OWNER_ID, function (User $user): void { + $user->getPermissions()->modListList = true; + }); + + $I->amOnPage('/mod-list/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->dontSeeLink('Create mod list'); + $I->seeActionButton('Download mod list'); + $I->seeActionButton('Edit mod list', '/mod-list/CUP/update'); + $I->dontSeeActionButton('Copy and edit mod list'); + $I->seeActionButton('Delete mod list', '/mod-list/CUP/delete'); + } + + public function listModListsAsAuthorizedUserWithCopyModListPermission(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User3Fixture::ID, function (User $user): void { + $user->getPermissions()->modListList = true; + $user->getPermissions()->modListCopy = true; + }); + + $I->amOnPage('/mod-list/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->dontSeeLink('Create mod list'); + $I->seeActionButton('Download mod list'); + $I->dontSeeActionButton('Edit mod list'); + $I->seeActionButton('Copy and edit mod list'); + $I->dontSeeActionButton('Delete mod list'); + } + + public function listModListsAsAuthorizedUserWithDeleteModListPermission(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User3Fixture::ID, function (User $user): void { + $user->getPermissions()->modListList = true; + $user->getPermissions()->modListDelete = true; + }); + + $I->amOnPage('/mod-list/list'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->dontSeeLink('Create mod list'); + $I->seeActionButton('Download mod list'); + $I->dontSeeActionButton('Edit mod list'); + $I->dontSeeActionButton('Copy and edit mod list'); + $I->seeActionButton('Delete mod list'); + } +} diff --git a/tests/functional/Web/ModList/UpdateModListCest.php b/tests/functional/Web/ModList/UpdateModListCest.php new file mode 100644 index 00000000..de39c39f --- /dev/null +++ b/tests/functional/Web/ModList/UpdateModListCest.php @@ -0,0 +1,347 @@ +stopFollowingRedirects(); + $I->freezeTime('2021-01-01T00:00:00+00:00'); + } + + public function updateModListAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage(sprintf('/mod-list/%s/update', RhsModListFixture::NAME)); + + $I->seeResponseRedirectsToLogInAction(); + } + + public function updateModListAsUnauthorizedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage(sprintf('/mod-list/%s/update', RhsModListFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + } + + public function updateModListAsAuthorizedUser(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modListUpdate = true; + }); + + $I->amOnPage(sprintf('/mod-list/%s/update', RhsModListFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeInField('Mod list name', 'RHS'); + $I->seeInField('Mod list description', ''); + $I->seeOptionIsSelected('Mod list owner', User2Fixture::USERNAME); + $I->dontSeeCheckboxIsChecked('Mod list active'); + $I->dontSee('Mod list approved'); + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_modGroups_', [ + RhsModGroupFixture::ID, + ]); // Some checkboxes checked + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_dlcs_', [ + CslaIronCurtainDlcFixture::ID, + ]); // Some checkboxes checked + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_mods_', [ + R3ModFixture::ID, + ArmaScriptProfilerModFixture::ID, + + AceInteractionMenuExpansionModFixture::ID, + ArmaForcesAceMedicalModFixture::ID, + LegacyArmaForcesModsModFixture::ID, + ArmaForcesJbadBuildingFixModFixture::ID, + ArmaForcesMedicalModFixture::ID, + ]); // Some checkboxes checked + + // Fill form + $I->fillField('Mod list name', 'Custom'); + $I->fillField('Mod list description', 'Custom modlist'); + $I->selectOption('Mod list owner', User3Fixture::USERNAME); + $I->checkOption('Mod list active'); + $I->uncheckTableRowCheckbox(RhsModGroupFixture::ID); // Mod group + $I->checkTableRowCheckbox(CupModGroupFixture::ID); // Mod group + $I->uncheckTableRowCheckbox(CslaIronCurtainDlcFixture::ID); // DLC + $I->checkTableRowCheckbox(SogPrairieFireDlcFixture::ID); // DLC + $I->uncheckTableRowCheckbox(R3ModFixture::ID); // Mod + $I->uncheckTableRowCheckbox(ArmaScriptProfilerModFixture::ID); // Mod + $I->click('Apply'); + + $I->seeResponseRedirectsTo('/mod-list/list'); + + /** @var ModList $modList */ + $modList = $I->grabEntityFromRepository(ModList::class, ['name' => 'Custom']); + $I->assertSame('Custom', $modList->getName()); + $I->assertSame('Custom modlist', $modList->getDescription()); + $I->assertSame(User3Fixture::ID, $modList->getOwner()->getId()->toString()); + $I->assertSame(true, $modList->isActive()); + $I->assertSame(false, $modList->isApproved()); + $I->assertSame([ + CupModGroupFixture::ID, + ], array_map(fn (ModGroup $modGroup) => $modGroup->getId()->toString(), $modList->getModGroups())); + $I->assertSame([ + SogPrairieFireDlcFixture::ID, + ], array_map(fn (Dlc $dlc) => $dlc->getId()->toString(), $modList->getDlcs())); + $I->assertSame([ + AceInteractionMenuExpansionModFixture::ID, + ArmaForcesAceMedicalModFixture::ID, + LegacyArmaForcesModsModFixture::ID, + ArmaForcesJbadBuildingFixModFixture::ID, + ArmaForcesMedicalModFixture::ID, + ], array_map(fn (AbstractMod $mod) => $mod->getId()->toString(), $modList->getMods())); + + $I->assertSame('2020-01-01T00:00:00+00:00', $modList->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame(RhsModListFixture::OWNER_ID, $modList->getCreatedBy()->getId()->toString()); + $I->assertSame('2021-01-01T00:00:00+00:00', $modList->getLastUpdatedAt()?->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $modList->getLastUpdatedBy()?->getId()->toString()); + } + + public function updateModListAsAuthorizedUserWithModListApprovePermission(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modListUpdate = true; + $user->getPermissions()->modListApprove = true; + }); + + $I->amOnPage(sprintf('/mod-list/%s/update', RhsModListFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeInField('Mod list name', 'RHS'); + $I->seeInField('Mod list description', ''); + $I->seeOptionIsSelected('Mod list owner', User2Fixture::USERNAME); + $I->dontSeeCheckboxIsChecked('Mod list active'); + $I->dontSeeCheckboxIsChecked('Mod list approved'); + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_modGroups_', [ + RhsModGroupFixture::ID, + ]); // Some checkboxes checked + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_dlcs_', [ + CslaIronCurtainDlcFixture::ID, + ]); // Some checkboxes checked + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_mods_', [ + R3ModFixture::ID, + ArmaScriptProfilerModFixture::ID, + + AceInteractionMenuExpansionModFixture::ID, + ArmaForcesAceMedicalModFixture::ID, + LegacyArmaForcesModsModFixture::ID, + ArmaForcesJbadBuildingFixModFixture::ID, + ArmaForcesMedicalModFixture::ID, + ]); // Some checkboxes checked + + // Fill form + $I->fillField('Mod list name', 'Custom'); + $I->fillField('Mod list description', 'Custom modlist'); + $I->selectOption('Mod list owner', User3Fixture::USERNAME); + $I->checkOption('Mod list active'); + $I->checkOption('Mod list approved'); + $I->uncheckTableRowCheckbox(RhsModGroupFixture::ID); // Mod group + $I->checkTableRowCheckbox(CupModGroupFixture::ID); // Mod group + $I->uncheckTableRowCheckbox(CslaIronCurtainDlcFixture::ID); // DLC + $I->checkTableRowCheckbox(SogPrairieFireDlcFixture::ID); // DLC + $I->uncheckTableRowCheckbox(R3ModFixture::ID); // Mod + $I->uncheckTableRowCheckbox(ArmaScriptProfilerModFixture::ID); // Mod + $I->click('Apply'); + + $I->seeResponseRedirectsTo('/mod-list/list'); + + /** @var ModList $modList */ + $modList = $I->grabEntityFromRepository(ModList::class, ['name' => 'Custom']); + $I->assertSame('Custom', $modList->getName()); + $I->assertSame('Custom modlist', $modList->getDescription()); + $I->assertSame(User3Fixture::ID, $modList->getOwner()->getId()->toString()); + $I->assertSame(true, $modList->isActive()); + $I->assertSame(true, $modList->isApproved()); + $I->assertSame([ + CupModGroupFixture::ID, + ], array_map(fn (ModGroup $modGroup) => $modGroup->getId()->toString(), $modList->getModGroups())); + $I->assertSame([ + SogPrairieFireDlcFixture::ID, + ], array_map(fn (Dlc $dlc) => $dlc->getId()->toString(), $modList->getDlcs())); + $I->assertSame([ + AceInteractionMenuExpansionModFixture::ID, + ArmaForcesAceMedicalModFixture::ID, + LegacyArmaForcesModsModFixture::ID, + ArmaForcesJbadBuildingFixModFixture::ID, + ArmaForcesMedicalModFixture::ID, + ], array_map(fn (AbstractMod $mod) => $mod->getId()->toString(), $modList->getMods())); + + $I->assertSame('2020-01-01T00:00:00+00:00', $modList->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame(RhsModListFixture::OWNER_ID, $modList->getCreatedBy()->getId()->toString()); + $I->assertSame('2021-01-01T00:00:00+00:00', $modList->getLastUpdatedAt()?->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $modList->getLastUpdatedBy()?->getId()->toString()); + } + + public function updateModListAsModListOwner(FunctionalTester $I): void + { + $currentUser = $I->amDiscordAuthenticatedAs(RhsModListFixture::OWNER_ID, function (User $user): void { + $user->getPermissions()->modListUpdate = false; + }); + + $I->amOnPage(sprintf('/mod-list/%s/update', RhsModListFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + + // Default form values + $I->seeInField('Mod list name', 'RHS'); + $I->seeInField('Mod list description', ''); + $I->dontSee('Mod list owner'); + $I->dontSeeCheckboxIsChecked('Mod list active'); + $I->dontSee('Mod list approved'); + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_modGroups_', [ + RhsModGroupFixture::ID, + ]); // Some checkboxes checked + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_dlcs_', [ + CslaIronCurtainDlcFixture::ID, + ]); // Some checkboxes checked + $I->seeTableRowCheckboxesAreUnchecked('mod_list_form_mods_', [ + R3ModFixture::ID, + ArmaScriptProfilerModFixture::ID, + + AceInteractionMenuExpansionModFixture::ID, + ArmaForcesAceMedicalModFixture::ID, + LegacyArmaForcesModsModFixture::ID, + ArmaForcesJbadBuildingFixModFixture::ID, + ArmaForcesMedicalModFixture::ID, + ]); // Some checkboxes checked + + // Fill form + $I->fillField('Mod list name', 'Custom'); + $I->fillField('Mod list description', 'Custom modlist'); + $I->checkOption('Mod list active'); + $I->uncheckTableRowCheckbox(RhsModGroupFixture::ID); // Mod group + $I->checkTableRowCheckbox(CupModGroupFixture::ID); // Mod group + $I->uncheckTableRowCheckbox(CslaIronCurtainDlcFixture::ID); // DLC + $I->checkTableRowCheckbox(SogPrairieFireDlcFixture::ID); // DLC + $I->uncheckTableRowCheckbox(R3ModFixture::ID); // Mod + $I->uncheckTableRowCheckbox(ArmaScriptProfilerModFixture::ID); // Mod + $I->click('Apply'); + + $I->seeResponseRedirectsTo('/mod-list/list'); + + /** @var ModList $modList */ + $modList = $I->grabEntityFromRepository(ModList::class, ['name' => 'Custom']); + $I->assertSame('Custom', $modList->getName()); + $I->assertSame('Custom modlist', $modList->getDescription()); + $I->assertSame(RhsModListFixture::OWNER_ID, $modList->getOwner()->getId()->toString()); + $I->assertSame(true, $modList->isActive()); + $I->assertSame(false, $modList->isApproved()); + $I->assertSame([ + CupModGroupFixture::ID, + ], array_map(fn (ModGroup $modGroup) => $modGroup->getId()->toString(), $modList->getModGroups())); + $I->assertSame([ + SogPrairieFireDlcFixture::ID, + ], array_map(fn (Dlc $dlc) => $dlc->getId()->toString(), $modList->getDlcs())); + $I->assertSame([ + AceInteractionMenuExpansionModFixture::ID, + ArmaForcesAceMedicalModFixture::ID, + LegacyArmaForcesModsModFixture::ID, + ArmaForcesJbadBuildingFixModFixture::ID, + ArmaForcesMedicalModFixture::ID, + ], array_map(fn (AbstractMod $mod) => $mod->getId()->toString(), $modList->getMods())); + + $I->assertSame('2020-01-01T00:00:00+00:00', $modList->getCreatedAt()->format(DATE_ATOM)); + $I->assertSame(RhsModListFixture::OWNER_ID, $modList->getCreatedBy()->getId()->toString()); + $I->assertSame('2021-01-01T00:00:00+00:00', $modList->getLastUpdatedAt()?->format(DATE_ATOM)); + $I->assertSame($currentUser->getId()->toString(), $modList->getLastUpdatedBy()?->getId()->toString()); + } + + public function updateModListAsAuthorizedUserWhenModListAlreadyExists(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modListUpdate = true; + }); + + $I->amOnPage(sprintf('/mod-list/%s/update', RhsModListFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Mod list name', DefaultModListFixture::NAME); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'Mod list with the same name "Default" already exist.'); + } + + public function updateModListAsAuthorizedUserWithoutRequiredData(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modListUpdate = true; + }); + + $I->amOnPage(sprintf('/mod-list/%s/update', RhsModListFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Mod list name', ''); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'This value should not be blank.'); + } + + public function updateModListAsAuthorizedUserWithDataTooLong(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modListUpdate = true; + }); + + $I->amOnPage(sprintf('/mod-list/%s/update', RhsModListFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->fillField('Mod list name', str_repeat('a', 256)); + $I->fillField('Mod list description', str_repeat('a', 256)); + $I->click('Apply'); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeFormErrorMessage('name', 'This value is too long. It should have 255 characters or less.'); + $I->seeFormErrorMessage('description', 'This value is too long. It should have 255 characters or less.'); + } + + public function updateModListAsAuthorizedUserWhenModListDoesNotExist(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID, function (User $user): void { + $user->getPermissions()->modListUpdate = true; + }); + + $I->amOnPage(sprintf('/mod-list/%s/update', 'non existing')); + + $I->seeResponseCodeIs(HttpCode::NOT_FOUND); + } +} From 2fc13eb1ed3e86ffc98ee23a3e7f2e482488d489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Skowro=C5=84ski?= Date: Wed, 10 Jan 2024 22:53:48 +0100 Subject: [PATCH 15/17] Add mod list public tests --- .../ModListPublic/DownloadAction.php | 4 +- .../_partial/_optional_mods_tab.html.twig | 4 +- tests/_support/Helper/Functional.php | 12 -- .../ModListPublic/CustomizeModListCest.php | 54 +++++++++ .../Web/ModListPublic/DownloadModListCest.php | 111 ++++++++++++++++++ .../Web/ModListPublic/SelectModListCest.php | 34 ++++++ 6 files changed, 204 insertions(+), 15 deletions(-) delete mode 100644 tests/_support/Helper/Functional.php create mode 100644 tests/functional/Web/ModListPublic/CustomizeModListCest.php create mode 100644 tests/functional/Web/ModListPublic/DownloadModListCest.php create mode 100644 tests/functional/Web/ModListPublic/SelectModListCest.php diff --git a/src/Controller/ModListPublic/DownloadAction.php b/src/Controller/ModListPublic/DownloadAction.php index e476648c..dc50c1c9 100644 --- a/src/Controller/ModListPublic/DownloadAction.php +++ b/src/Controller/ModListPublic/DownloadAction.php @@ -13,6 +13,8 @@ use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Http\Attribute\IsGranted; +use function Symfony\Component\Clock\now; + class DownloadAction extends AbstractController { public function __construct( @@ -24,7 +26,7 @@ public function __construct( #[IsGranted(PermissionsEnum::MOD_LIST_DOWNLOAD->value, 'modList')] public function __invoke(ModList $modList, string $optionalModsJson = null): Response { - $name = sprintf('ArmaForces %s %s', $modList->getName(), (new \DateTimeImmutable())->format('Y_m_d H_i')); + $name = sprintf('ArmaForces %s %s', $modList->getName(), now()->format('Y_m_d H_i')); $mods = $this->modRepository->findIncludedSteamWorkshopMods($modList); $optionalMods = json_decode($optionalModsJson ?? '', true) ?: []; diff --git a/templates/mod_list_public/_partial/_optional_mods_tab.html.twig b/templates/mod_list_public/_partial/_optional_mods_tab.html.twig index 55f9d104..5fdee2bb 100644 --- a/templates/mod_list_public/_partial/_optional_mods_tab.html.twig +++ b/templates/mod_list_public/_partial/_optional_mods_tab.html.twig @@ -23,10 +23,10 @@ {{ tableMacro.row_mod_status_icon(mod) }} {{ tableMacro.row_name_with_description(mod.name, mod.description) }} - {% set modEntryId = 'mod-' ~ mod.id %} + {% set modEntryId = 'optional-mod-' ~ mod.id %}
          - +
          diff --git a/tests/_support/Helper/Functional.php b/tests/_support/Helper/Functional.php deleted file mode 100644 index eb527c98..00000000 --- a/tests/_support/Helper/Functional.php +++ /dev/null @@ -1,12 +0,0 @@ -freezeTime('2020-01-01T00:00:00+00:00'); + } + + public function customizeModListAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage(sprintf('/mod-list/%s', DefaultModListFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeTableRowCheckboxesAreUnchecked('optional-mod-'); // All checkboxes are unchecked + + $I->seeLink('Download'); + $I->seeLink('Download required'); + } + + public function customizeModListAsAuthenticatedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage(sprintf('/mod-list/%s', DefaultModListFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + + $I->seeTableRowCheckboxesAreUnchecked('optional-mod-'); // All checkboxes are unchecked + + $I->seeLink('Download'); + $I->seeLink('Download required'); + } + + public function customizeModListAsAuthenticatedUserWhenModListInactive(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage(sprintf('/mod-list/%s', RhsModListFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + } +} diff --git a/tests/functional/Web/ModListPublic/DownloadModListCest.php b/tests/functional/Web/ModListPublic/DownloadModListCest.php new file mode 100644 index 00000000..226e4c34 --- /dev/null +++ b/tests/functional/Web/ModListPublic/DownloadModListCest.php @@ -0,0 +1,111 @@ +freezeTime('2020-01-01T00:00:00+00:00'); + } + + public function downloadModListAsUnauthenticatedUser(FunctionalTester $I): void + { + $optionalMods = [ + AceInteractionMenuExpansionModFixture::ID, + 'invalid', + ]; + + $I->amOnPage(sprintf('/mod-list/%s/download/%s', DefaultModListFixture::NAME, json_encode($optionalMods))); + + $I->seeResponseContainsModListPresetWithMods('ArmaForces Default 2020_01_01 00_00.html', [ + $I->grabEntityFromRepository(Dlc::class, ['id' => CslaIronCurtainDlcFixture::ID]), + $I->grabEntityFromRepository(Dlc::class, ['id' => GlobalMobilizationDlcFixture::ID]), + $I->grabEntityFromRepository(Dlc::class, ['id' => SogPrairieFireDlcFixture::ID]), + $I->grabEntityFromRepository(Dlc::class, ['id' => Spearhead1944DlcFixture::ID]), + ], [ + $I->grabEntityFromRepository(SteamWorkshopMod::class, ['id' => ArmaForcesAceMedicalModFixture::ID]), + $I->grabEntityFromRepository(SteamWorkshopMod::class, ['id' => ArmaForcesMedicalModFixture::ID]), + $I->grabEntityFromRepository(SteamWorkshopMod::class, ['id' => CupTerrainsCoreModFixture::ID]), + $I->grabEntityFromRepository(SteamWorkshopMod::class, ['id' => CupTerrainsMapsModFixture::ID]), + $I->grabEntityFromRepository(SteamWorkshopMod::class, ['id' => CupUnitsModFixture::ID]), + $I->grabEntityFromRepository(SteamWorkshopMod::class, ['id' => CupVehiclesModFixture::ID]), + $I->grabEntityFromRepository(SteamWorkshopMod::class, ['id' => CupWeaponsModFixture::ID]), + $I->grabEntityFromRepository(SteamWorkshopMod::class, ['id' => RhsAfrfModFixture::ID]), + $I->grabEntityFromRepository(SteamWorkshopMod::class, ['id' => RhsGrefModFixture::ID]), + $I->grabEntityFromRepository(SteamWorkshopMod::class, ['id' => RhsUsafModFixture::ID]), + $I->grabEntityFromRepository(SteamWorkshopMod::class, ['id' => LegacyArmaForcesModsModFixture::ID]), + ]); + } + + public function downloadModListAsAuthenticatedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $optionalMods = [ + AceInteractionMenuExpansionModFixture::ID, + 'invalid', + ]; + + $I->amOnPage(sprintf('/mod-list/%s/download/%s', DefaultModListFixture::NAME, json_encode($optionalMods))); + + $I->seeResponseContainsModListPresetWithMods('ArmaForces Default 2020_01_01 00_00.html', [ + $I->grabEntityFromRepository(Dlc::class, ['id' => CslaIronCurtainDlcFixture::ID]), + $I->grabEntityFromRepository(Dlc::class, ['id' => GlobalMobilizationDlcFixture::ID]), + $I->grabEntityFromRepository(Dlc::class, ['id' => SogPrairieFireDlcFixture::ID]), + $I->grabEntityFromRepository(Dlc::class, ['id' => Spearhead1944DlcFixture::ID]), + ], [ + $I->grabEntityFromRepository(SteamWorkshopMod::class, ['id' => ArmaForcesAceMedicalModFixture::ID]), + $I->grabEntityFromRepository(SteamWorkshopMod::class, ['id' => ArmaForcesMedicalModFixture::ID]), + $I->grabEntityFromRepository(SteamWorkshopMod::class, ['id' => CupTerrainsCoreModFixture::ID]), + $I->grabEntityFromRepository(SteamWorkshopMod::class, ['id' => CupTerrainsMapsModFixture::ID]), + $I->grabEntityFromRepository(SteamWorkshopMod::class, ['id' => CupUnitsModFixture::ID]), + $I->grabEntityFromRepository(SteamWorkshopMod::class, ['id' => CupVehiclesModFixture::ID]), + $I->grabEntityFromRepository(SteamWorkshopMod::class, ['id' => CupWeaponsModFixture::ID]), + $I->grabEntityFromRepository(SteamWorkshopMod::class, ['id' => RhsAfrfModFixture::ID]), + $I->grabEntityFromRepository(SteamWorkshopMod::class, ['id' => RhsGrefModFixture::ID]), + $I->grabEntityFromRepository(SteamWorkshopMod::class, ['id' => RhsUsafModFixture::ID]), + $I->grabEntityFromRepository(SteamWorkshopMod::class, ['id' => LegacyArmaForcesModsModFixture::ID]), + ]); + } + + public function downloadModListAsAuthenticatedUserWhenModListInactive(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $optionalMods = [ + AceInteractionMenuExpansionModFixture::ID, + 'invalid', + ]; + + $I->amOnPage(sprintf('/mod-list/%s/download/%s', RhsModListFixture::NAME, json_encode($optionalMods))); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + } +} diff --git a/tests/functional/Web/ModListPublic/SelectModListCest.php b/tests/functional/Web/ModListPublic/SelectModListCest.php new file mode 100644 index 00000000..ac4944e9 --- /dev/null +++ b/tests/functional/Web/ModListPublic/SelectModListCest.php @@ -0,0 +1,34 @@ +amOnPage('/mod-list/select'); + + $I->see(DefaultModListFixture::NAME); + $I->see(CupModListFixture::NAME); + $I->dontSee(RhsModListFixture::NAME); // disabled + } + + public function selectModListAsAuthenticatedUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage('/mod-list/select'); + + $I->see(DefaultModListFixture::NAME); + $I->see(CupModListFixture::NAME); + $I->dontSee(RhsModListFixture::NAME); // disabled + } +} From 29672badd76256e56832077a624f3663f2c3c560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Skowro=C5=84ski?= Date: Wed, 10 Jan 2024 22:54:33 +0100 Subject: [PATCH 16/17] Add attendance api tests --- .../Api/Attendance/CreateAttendanceCest.php | 120 ++++++++++++++++++ .../Api/Attendance/ListAttendancesCest.php | 94 ++++++++++++++ tests/functional/Web/Api/IndexCest.php | 45 +++++++ 3 files changed, 259 insertions(+) create mode 100644 tests/functional/Api/Attendance/CreateAttendanceCest.php create mode 100644 tests/functional/Api/Attendance/ListAttendancesCest.php create mode 100644 tests/functional/Web/Api/IndexCest.php diff --git a/tests/functional/Api/Attendance/CreateAttendanceCest.php b/tests/functional/Api/Attendance/CreateAttendanceCest.php new file mode 100644 index 00000000..60c6ff8e --- /dev/null +++ b/tests/functional/Api/Attendance/CreateAttendanceCest.php @@ -0,0 +1,120 @@ +haveHttpHeader('Accept', 'application/json'); + $I->haveHttpHeader('Content-Type', 'application/json'); + } + + public function createAttendanceWithoutApiKey(FunctionalTester $I): void + { + $I->sendPost('/api/attendances', [ + 'missionId' => 'mission_99', + 'playerId' => 76561198048200529, + ]); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + $I->seeResponseContainsJson([ + 'detail' => 'Invalid or missing API key provided!', + ]); + + $I->dontSeeInRepository(Attendance::class, ['missionId' => 'mission_99']); + } + + public function createAttendanceUsingInvalidApiKey(FunctionalTester $I): void + { + $I->amApiKeyAuthenticatedAs('invalid_key'); + + $I->sendPost('/api/attendances', [ + 'missionId' => 'mission_99', + 'playerId' => 76561198048200529, + ]); + + $I->seeResponseCodeIs(HttpCode::FORBIDDEN); + $I->seeResponseContainsJson([ + 'detail' => 'Invalid or missing API key provided!', + ]); + + $I->dontSeeInRepository(Attendance::class, ['missionId' => 'mission_99']); + } + + public function createAttendanceUsingApiKey(FunctionalTester $I): void + { + $I->amApiKeyAuthenticatedAs('test_key'); + + $I->sendPost('/api/attendances', [ + 'missionId' => 'mission_99', + 'playerId' => 76561198048200529, + ]); + + $I->seeResponseCodeIs(HttpCode::CREATED); + + /** @var Attendance $attendance */ + $attendance = $I->grabEntityFromRepository(Attendance::class, ['missionId' => 'mission_99']); + $I->assertSame('mission_99', $attendance->getMissionId()); + $I->assertSame(76561198048200529, $attendance->getPlayerId()); + } + + public function createAttendanceUsingApiKeyWhenAttendanceAlreadyExist(FunctionalTester $I): void + { + $I->amApiKeyAuthenticatedAs('test_key'); + + $I->sendPost('/api/attendances', [ + 'missionId' => 'mission_1', + 'playerId' => 76561198048200529, + ]); + + $I->seeResponseCodeIs(HttpCode::UNPROCESSABLE_ENTITY); + $I->seeResponseContainsJson([ + 'detail' => 'Attendance of player "76561198048200529" in mission "mission_1" already exists.', + ]); + + /** @var Attendance[] $attendances */ + $attendances = $I->grabEntitiesFromRepository(Attendance::class, ['missionId' => 'mission_1']); + $I->assertCount(1, $attendances); + } + + public function createAttendanceUsingApiKeyWithDataTooLong(FunctionalTester $I): void + { + $I->amApiKeyAuthenticatedAs('test_key'); + + $I->sendPost('/api/attendances', [ + 'missionId' => str_repeat('a', 256), + 'playerId' => 76561198048200529, + ]); + + $I->seeResponseCodeIs(HttpCode::UNPROCESSABLE_ENTITY); + $I->seeResponseContainsJson([ + 'detail' => 'missionId: This value is too long. It should have 255 characters or less.', + ]); + + $I->dontSeeInRepository(Attendance::class, ['missionId' => 'mission_99']); + } + + public function createAttendanceUsingApiKeyWithInvalidPlayerId(FunctionalTester $I): void + { + $I->amApiKeyAuthenticatedAs('test_key'); + + $I->sendPost('/api/attendances', [ + 'missionId' => 'mission_99', + 'playerId' => 123, + ]); + + $I->seeResponseCodeIs(HttpCode::UNPROCESSABLE_ENTITY); + $I->seeResponseContainsJson([ + 'detail' => 'playerId: Invalid Steam profile ID.', + ]); + + $I->dontSeeInRepository(Attendance::class, ['missionId' => 'mission_99']); + } +} diff --git a/tests/functional/Api/Attendance/ListAttendancesCest.php b/tests/functional/Api/Attendance/ListAttendancesCest.php new file mode 100644 index 00000000..a089bc44 --- /dev/null +++ b/tests/functional/Api/Attendance/ListAttendancesCest.php @@ -0,0 +1,94 @@ +haveHttpHeader('Accept', 'application/json'); + $I->haveHttpHeader('Content-Type', 'application/json'); + } + + public function listAttendancesWithoutApiKey(FunctionalTester $I): void + { + $I->sendGet('/api/attendances', [ + 'order[missionId]' => 'ASC', + ]); + + $I->seeResponseCodeIs(HttpCode::OK); + $I->seeResponseContainsJson($this->getExpectedPayload()); + } + + public function listAttendancesUsingInvalidApiKey(FunctionalTester $I): void + { + $I->amApiKeyAuthenticatedAs('invalid_key'); + + $I->sendGet('/api/attendances', [ + 'order[missionId]' => 'ASC', + ]); + + $I->seeResponseCodeIs(HttpCode::OK); + $I->seeResponseContainsJson($this->getExpectedPayload()); + } + + public function listAttendancesUsingValidApiKey(FunctionalTester $I): void + { + $I->amApiKeyAuthenticatedAs('test_key'); + + $I->sendGet('/api/attendances', [ + 'order[missionId]' => 'ASC', + ]); + + $I->seeResponseCodeIs(HttpCode::OK); + $I->seeResponseContainsJson($this->getExpectedPayload()); + } + + private function getExpectedPayload(): array + { + return [ + 'data' => [ + [ + 'id' => '2694264f-0e6f-40a6-9596-bc22d1eaa2c7', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'missionId' => 'mission_1', + 'playerId' => 76561198048200529, + ], + [ + 'id' => 'd2a60cd4-d3f0-497a-9840-69fa5c388f1e', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'missionId' => 'mission_2', + 'playerId' => 76561198048200529, + ], + [ + 'id' => '0a918bf1-d20f-4856-aa0d-f093f6e90bf7', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'missionId' => 'mission_3', + 'playerId' => 76561198048200529, + ], + [ + 'id' => '2a3aa170-3a79-471f-b6ec-e194bf8d6c9e', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'missionId' => 'mission_4', + 'playerId' => 76561198048200529, + ], + [ + 'id' => 'ac22546b-9d5c-4a54-a713-01dcc5ee40e6', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'missionId' => 'mission_5', + 'playerId' => 76561198048200529, + ], + ], + 'items' => 5, + 'totalItems' => 5.0, + 'currentPage' => 1.0, + 'lastPage' => 1.0, + 'itemsPerPage' => 30.0, + ]; + } +} diff --git a/tests/functional/Web/Api/IndexCest.php b/tests/functional/Web/Api/IndexCest.php new file mode 100644 index 00000000..5a3fddee --- /dev/null +++ b/tests/functional/Web/Api/IndexCest.php @@ -0,0 +1,45 @@ +haveHttpHeader('Accept', 'text/html'); + } + + public function visitApiDocsPageAsUnauthenticatedUser(FunctionalTester $I): void + { + $I->amOnPage('/api'); + + $I->seeResponseCodeIs(200); + $I->see('ArmaForces Website Web API'); + } + + public function visitApiDocsPageAsRegisteredUser(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(User1Fixture::ID); + + $I->amOnPage('/api'); + + $I->seeResponseCodeIs(200); + $I->see('ArmaForces Website Web API'); + } + + public function visitApiDocsPageAsRegisteredUserWithFullPermissions(FunctionalTester $I): void + { + $I->amDiscordAuthenticatedAs(AdminFixture::ID); + + $I->amOnPage('/api'); + + $I->seeResponseCodeIs(200); + $I->see('ArmaForces Website Web API'); + } +} From 98b956288b79bea621e7a8e8891d0415a47ac5d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Skowro=C5=84ski?= Date: Wed, 10 Jan 2024 22:54:40 +0100 Subject: [PATCH 17/17] Add mod list api tests --- .../Api/ModList/GetModListsByIdCest.php | 273 ++++++++++++++++++ .../Api/ModList/GetModListsByNameCest.php | 273 ++++++++++++++++++ .../Api/ModList/ListModListsCest.php | 88 ++++++ 3 files changed, 634 insertions(+) create mode 100644 tests/functional/Api/ModList/GetModListsByIdCest.php create mode 100644 tests/functional/Api/ModList/GetModListsByNameCest.php create mode 100644 tests/functional/Api/ModList/ListModListsCest.php diff --git a/tests/functional/Api/ModList/GetModListsByIdCest.php b/tests/functional/Api/ModList/GetModListsByIdCest.php new file mode 100644 index 00000000..faa915ef --- /dev/null +++ b/tests/functional/Api/ModList/GetModListsByIdCest.php @@ -0,0 +1,273 @@ +haveHttpHeader('Accept', 'application/json'); + $I->haveHttpHeader('Content-Type', 'application/json'); + } + + public function getModListByIdWithoutApiKey(FunctionalTester $I): void + { + $I->sendGet(sprintf('/api/mod-lists/%s', DefaultModListFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + $I->seeResponseContainsJson($this->getExpectedPayload()); + } + + public function getModListByIdUsingInvalidApiKey(FunctionalTester $I): void + { + $I->amApiKeyAuthenticatedAs('invalid_key'); + + $I->sendGet(sprintf('/api/mod-lists/%s', DefaultModListFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + $I->seeResponseContainsJson($this->getExpectedPayload()); + } + + public function getModListByIdUsingValidApiKey(FunctionalTester $I): void + { + $I->amApiKeyAuthenticatedAs('test_key'); + + $I->sendGet(sprintf('/api/mod-lists/%s', DefaultModListFixture::ID)); + + $I->seeResponseCodeIs(HttpCode::OK); + $I->seeResponseContainsJson($this->getExpectedPayload()); + } + + public function getModListByIdUsingValidApiKeyWhenModListDoesNotExist(FunctionalTester $I): void + { + $I->amApiKeyAuthenticatedAs('test_key'); + + $I->sendGet(sprintf('/api/mod-lists/%s', 'd2cca3c6-1c5f-4ea7-afcf-a05317a58467')); + + $I->seeResponseCodeIs(HttpCode::NOT_FOUND); + $I->seeResponseContainsJson([ + 'type' => 'https://tools.ietf.org/html/rfc2616#section-10', + 'title' => 'An error occurred', + 'detail' => 'Not Found', + ]); + } + + private function getExpectedPayload(): array + { + return [ + 'mods' => [ + [ + 'id' => '37f58e30-5194-4594-89af-4a82c7fc02be', + 'name' => 'ACE Interaction Menu Expansion', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => null, + 'type' => 'optional', + 'itemId' => 1376867375, + 'directory' => null, + ], + [ + 'id' => '5506ae1b-2851-40e7-a15a-48f1fe6daaed', + 'name' => 'Arma Script Profiler', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'directory', + 'status' => null, + 'type' => 'server_side', + 'itemId' => null, + 'directory' => '@Arma Script Profiler', + ], + [ + 'id' => '2f1d2dea-a7a6-4509-b478-66a980d724ca', + 'name' => 'ArmaForces - ACE Medical [OBSOLETE]', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => 'broken', + 'type' => 'required', + 'itemId' => 1704054308, + 'directory' => null, + ], + [ + 'id' => '0e4e059c-eef6-42a9-aec3-abdab344ec21', + 'name' => 'ArmaForces - Medical', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => null, + 'type' => 'required', + 'itemId' => 1981535406, + 'directory' => null, + ], + [ + 'id' => '3e67f919-6880-4299-a2af-11b76ec594e6', + 'name' => 'CUP Terrains - Core', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => null, + 'type' => 'required', + 'itemId' => 583496184, + 'directory' => null, + ], + [ + 'id' => '86b6e354-055a-4d8d-a877-ca4bb2f58a2e', + 'name' => 'CUP Terrains - Maps', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => null, + 'type' => 'required', + 'itemId' => 583544987, + 'directory' => null, + ], + [ + 'id' => '7f55e10e-e005-4852-9a3f-1e28ae53414c', + 'name' => 'CUP Units', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => null, + 'type' => 'required', + 'itemId' => 497661914, + 'directory' => null, + ], + [ + 'id' => '7275d787-d3c2-43b3-a2fa-cc881b1b052f', + 'name' => 'CUP Vehicles', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => null, + 'type' => 'required', + 'itemId' => 541888371, + 'directory' => null, + ], + [ + 'id' => '6b177a8c-8289-46c6-9a6a-401d0c841edf', + 'name' => 'CUP Weapons', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => null, + 'type' => 'required', + 'itemId' => 497660133, + 'directory' => null, + ], + [ + 'id' => '50b2c68a-1ea0-44b8-9b4d-6e0a47627d47', + 'name' => 'R3', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'directory', + 'status' => 'deprecated', + 'type' => 'server_side', + 'itemId' => null, + 'directory' => '@R3', + ], + [ + 'id' => '91e0eaf1-3cf1-4b2c-98a9-a2d74a69fa76', + 'name' => 'RHS AFRF', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => null, + 'type' => 'required', + 'itemId' => 843425103, + 'directory' => null, + ], + [ + 'id' => 'a34b691c-50a2-475e-bd0a-43e707c45db5', + 'name' => 'RHS GREF', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => null, + 'type' => 'required', + 'itemId' => 843593391, + 'directory' => null, + ], + [ + 'id' => 'a37a6a74-3e82-4955-a836-0732d7816cc1', + 'name' => 'RHS USAF', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => null, + 'type' => 'required', + 'itemId' => 843577117, + 'directory' => null, + ], + [ + 'id' => 'b8e88103-69d2-438b-8d89-933ccfdb3a5a', + 'name' => '[OBSOLETE] ArmaForces - JBAD Building Fix', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => 'disabled', + 'type' => 'required', + 'itemId' => 1781106281, + 'directory' => null, + ], + [ + 'id' => '7e11c37e-930e-49e8-a87d-8f942d98edb0', + 'name' => '[legacy] ArmaForces - Mods', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => 'deprecated', + 'type' => 'required', + 'itemId' => 1639399387, + 'directory' => null, + ], + ], + 'dlcs' => [ + [ + 'id' => 'ebd772ce-e5b5-4813-9ad0-777915660d37', + 'name' => 'Arma 3 Creator DLC: CSLA Iron Curtain', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'appId' => 1294440, + 'directory' => 'csla', + ], + [ + 'id' => 'c2cd8ffd-0b4b-449b-aca5-cb91f16a9e54', + 'name' => 'Arma 3 Creator DLC: Global Mobilization - Cold War Germany', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'appId' => 1042220, + 'directory' => 'gm', + ], + [ + 'id' => '805dfa49-ef6b-4259-85c5-a09565174448', + 'name' => 'Arma 3 Creator DLC: S.O.G. Prairie Fire', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'appId' => 1227700, + 'directory' => 'vn', + ], + [ + 'id' => 'c42adf33-2f16-4bdf-bc38-66d7d037d677', + 'name' => 'Arma 3 Creator DLC: Spearhead 1944', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'appId' => 1175380, + 'directory' => 'spe', + ], + ], + 'id' => 'f3e04dae-18a8-4533-99ea-d6d763ebabcf', + 'name' => 'Default', + 'active' => true, + 'approved' => true, + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + ]; + } +} diff --git a/tests/functional/Api/ModList/GetModListsByNameCest.php b/tests/functional/Api/ModList/GetModListsByNameCest.php new file mode 100644 index 00000000..9fc29202 --- /dev/null +++ b/tests/functional/Api/ModList/GetModListsByNameCest.php @@ -0,0 +1,273 @@ +haveHttpHeader('Accept', 'application/json'); + $I->haveHttpHeader('Content-Type', 'application/json'); + } + + public function getModListByNameWithoutApiKey(FunctionalTester $I): void + { + $I->sendGet(sprintf('/api/mod-lists/by-name/%s', DefaultModListFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + $I->seeResponseContainsJson($this->getExpectedPayload()); + } + + public function getModListByNameUsingInvalidApiKey(FunctionalTester $I): void + { + $I->amApiKeyAuthenticatedAs('invalid_key'); + + $I->sendGet(sprintf('/api/mod-lists/by-name/%s', DefaultModListFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + $I->seeResponseContainsJson($this->getExpectedPayload()); + } + + public function getModListByNameUsingValidApiKey(FunctionalTester $I): void + { + $I->amApiKeyAuthenticatedAs('test_key'); + + $I->sendGet(sprintf('/api/mod-lists/by-name/%s', DefaultModListFixture::NAME)); + + $I->seeResponseCodeIs(HttpCode::OK); + $I->seeResponseContainsJson($this->getExpectedPayload()); + } + + public function getModListByNameUsingValidApiKeyWhenModListDoesNotExist(FunctionalTester $I): void + { + $I->amApiKeyAuthenticatedAs('test_key'); + + $I->sendGet(sprintf('/api/mod-lists/by-name/%s', 'non existing')); + + $I->seeResponseCodeIs(HttpCode::NOT_FOUND); + $I->seeResponseContainsJson([ + 'type' => 'https://tools.ietf.org/html/rfc2616#section-10', + 'title' => 'An error occurred', + 'detail' => 'Not Found', + ]); + } + + private function getExpectedPayload(): array + { + return [ + 'mods' => [ + [ + 'id' => '37f58e30-5194-4594-89af-4a82c7fc02be', + 'name' => 'ACE Interaction Menu Expansion', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => null, + 'type' => 'optional', + 'itemId' => 1376867375, + 'directory' => null, + ], + [ + 'id' => '5506ae1b-2851-40e7-a15a-48f1fe6daaed', + 'name' => 'Arma Script Profiler', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'directory', + 'status' => null, + 'type' => 'server_side', + 'itemId' => null, + 'directory' => '@Arma Script Profiler', + ], + [ + 'id' => '2f1d2dea-a7a6-4509-b478-66a980d724ca', + 'name' => 'ArmaForces - ACE Medical [OBSOLETE]', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => 'broken', + 'type' => 'required', + 'itemId' => 1704054308, + 'directory' => null, + ], + [ + 'id' => '0e4e059c-eef6-42a9-aec3-abdab344ec21', + 'name' => 'ArmaForces - Medical', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => null, + 'type' => 'required', + 'itemId' => 1981535406, + 'directory' => null, + ], + [ + 'id' => '3e67f919-6880-4299-a2af-11b76ec594e6', + 'name' => 'CUP Terrains - Core', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => null, + 'type' => 'required', + 'itemId' => 583496184, + 'directory' => null, + ], + [ + 'id' => '86b6e354-055a-4d8d-a877-ca4bb2f58a2e', + 'name' => 'CUP Terrains - Maps', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => null, + 'type' => 'required', + 'itemId' => 583544987, + 'directory' => null, + ], + [ + 'id' => '7f55e10e-e005-4852-9a3f-1e28ae53414c', + 'name' => 'CUP Units', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => null, + 'type' => 'required', + 'itemId' => 497661914, + 'directory' => null, + ], + [ + 'id' => '7275d787-d3c2-43b3-a2fa-cc881b1b052f', + 'name' => 'CUP Vehicles', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => null, + 'type' => 'required', + 'itemId' => 541888371, + 'directory' => null, + ], + [ + 'id' => '6b177a8c-8289-46c6-9a6a-401d0c841edf', + 'name' => 'CUP Weapons', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => null, + 'type' => 'required', + 'itemId' => 497660133, + 'directory' => null, + ], + [ + 'id' => '50b2c68a-1ea0-44b8-9b4d-6e0a47627d47', + 'name' => 'R3', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'directory', + 'status' => 'deprecated', + 'type' => 'server_side', + 'itemId' => null, + 'directory' => '@R3', + ], + [ + 'id' => '91e0eaf1-3cf1-4b2c-98a9-a2d74a69fa76', + 'name' => 'RHS AFRF', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => null, + 'type' => 'required', + 'itemId' => 843425103, + 'directory' => null, + ], + [ + 'id' => 'a34b691c-50a2-475e-bd0a-43e707c45db5', + 'name' => 'RHS GREF', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => null, + 'type' => 'required', + 'itemId' => 843593391, + 'directory' => null, + ], + [ + 'id' => 'a37a6a74-3e82-4955-a836-0732d7816cc1', + 'name' => 'RHS USAF', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => null, + 'type' => 'required', + 'itemId' => 843577117, + 'directory' => null, + ], + [ + 'id' => 'b8e88103-69d2-438b-8d89-933ccfdb3a5a', + 'name' => '[OBSOLETE] ArmaForces - JBAD Building Fix', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => 'disabled', + 'type' => 'required', + 'itemId' => 1781106281, + 'directory' => null, + ], + [ + 'id' => '7e11c37e-930e-49e8-a87d-8f942d98edb0', + 'name' => '[legacy] ArmaForces - Mods', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'source' => 'steam_workshop', + 'status' => 'deprecated', + 'type' => 'required', + 'itemId' => 1639399387, + 'directory' => null, + ], + ], + 'dlcs' => [ + [ + 'id' => 'ebd772ce-e5b5-4813-9ad0-777915660d37', + 'name' => 'Arma 3 Creator DLC: CSLA Iron Curtain', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'appId' => 1294440, + 'directory' => 'csla', + ], + [ + 'id' => 'c2cd8ffd-0b4b-449b-aca5-cb91f16a9e54', + 'name' => 'Arma 3 Creator DLC: Global Mobilization - Cold War Germany', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'appId' => 1042220, + 'directory' => 'gm', + ], + [ + 'id' => '805dfa49-ef6b-4259-85c5-a09565174448', + 'name' => 'Arma 3 Creator DLC: S.O.G. Prairie Fire', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'appId' => 1227700, + 'directory' => 'vn', + ], + [ + 'id' => 'c42adf33-2f16-4bdf-bc38-66d7d037d677', + 'name' => 'Arma 3 Creator DLC: Spearhead 1944', + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + 'appId' => 1175380, + 'directory' => 'spe', + ], + ], + 'id' => 'f3e04dae-18a8-4533-99ea-d6d763ebabcf', + 'name' => 'Default', + 'active' => true, + 'approved' => true, + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + ]; + } +} diff --git a/tests/functional/Api/ModList/ListModListsCest.php b/tests/functional/Api/ModList/ListModListsCest.php new file mode 100644 index 00000000..bc3c1ec2 --- /dev/null +++ b/tests/functional/Api/ModList/ListModListsCest.php @@ -0,0 +1,88 @@ +haveHttpHeader('Accept', 'application/json'); + $I->haveHttpHeader('Content-Type', 'application/json'); + } + + public function listModListsWithoutApiKey(FunctionalTester $I): void + { + $I->sendGet('/api/mod-lists', [ + 'order[name]' => 'ASC', + ]); + + $I->seeResponseCodeIs(HttpCode::OK); + $I->seeResponseContainsJson($this->getExpectedPayload()); + } + + public function listModListsUsingInvalidApiKey(FunctionalTester $I): void + { + $I->amApiKeyAuthenticatedAs('invalid_key'); + + $I->sendGet('/api/mod-lists', [ + 'order[name]' => 'ASC', + ]); + + $I->seeResponseCodeIs(HttpCode::OK); + $I->seeResponseContainsJson($this->getExpectedPayload()); + } + + public function listModListsUsingValidApiKey(FunctionalTester $I): void + { + $I->amApiKeyAuthenticatedAs('test_key'); + + $I->sendGet('/api/mod-lists', [ + 'order[name]' => 'ASC', + ]); + + $I->seeResponseCodeIs(HttpCode::OK); + $I->seeResponseContainsJson($this->getExpectedPayload()); + } + + private function getExpectedPayload(): array + { + return [ + 'data' => [ + [ + 'id' => 'ea384489-c06c-4844-9e56-0e9a9c46bfaf', + 'name' => 'CUP', + 'active' => true, + 'approved' => false, + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + ], + [ + 'id' => 'f3e04dae-18a8-4533-99ea-d6d763ebabcf', + 'name' => 'Default', + 'active' => true, + 'approved' => true, + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + ], + [ + 'id' => 'c3b11c2f-9254-4262-bfde-3605df0149d4', + 'name' => 'RHS', + 'active' => false, + 'approved' => false, + 'createdAt' => '2020-01-01T00:00:00+00:00', + 'lastUpdatedAt' => null, + ], + ], + 'items' => 3, + 'totalItems' => 3.0, + 'currentPage' => 1.0, + 'lastPage' => 1.0, + 'itemsPerPage' => 30.0, + ]; + } +}