feat: VivesPOS landing on Winter CMS 1.2 — theme + plugin + Dockerfile
Some checks are pending
Module sub-split / Sub-split (push) Waiting to run
Some checks are pending
Module sub-split / Sub-split (push) Waiting to run
- Base: wintercms/winter branch 1.2 (full framework) - Theme vivespos: Canvas 7 + Bootstrap 5 CDN, custom CSS - Layout: deferred GTM/GA4 tracking, JSON-LD SoftwareApplication - Partials: hero (offline-first), features, modes (offline/nube toggle), screenshots, pricing (3 planes), comparison, FAQ, CTA - Plugin VivesPOS.Site with ContactForm - Dockerfile: PHP 8.2 Apache, port 80, healthcheck - Added winter/wn-pages, blog, sitemap, seo plugins - Active theme set to vivespos
This commit is contained in:
26
modules/system/tests/AliasesTest.php
Normal file
26
modules/system/tests/AliasesTest.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests;
|
||||
|
||||
use System\Tests\Bootstrap\PluginTestCase;
|
||||
|
||||
class AliasesTest extends PluginTestCase
|
||||
{
|
||||
public function testInputFacadeAlias()
|
||||
{
|
||||
$this->assertTrue(class_exists('Illuminate\Support\Facades\Input'));
|
||||
$this->assertInstanceOf(
|
||||
\Winter\Storm\Support\Facades\Input::class,
|
||||
new \Illuminate\Support\Facades\Input()
|
||||
);
|
||||
}
|
||||
|
||||
public function testHtmlDumperAlias()
|
||||
{
|
||||
$this->assertTrue(class_exists('Illuminate\Support\Debug\HtmlDumper'));
|
||||
$this->assertInstanceOf(
|
||||
\Symfony\Component\VarDumper\Dumper\HtmlDumper::class,
|
||||
new \Illuminate\Support\Debug\HtmlDumper()
|
||||
);
|
||||
}
|
||||
}
|
||||
110
modules/system/tests/README.md
Normal file
110
modules/system/tests/README.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# Plugin testing
|
||||
|
||||
Individual plugin test cases can be run by running either `artisan winter:test -p MyAuthor.MyPlugin` in the project root or `../../../vendor/bin/phpunit` in the plugin's base directory (ex. `plugins/acme/demo`).
|
||||
|
||||
### Creating plugin tests
|
||||
|
||||
Plugins can be tested by creating a file called `phpunit.xml` in the base directory with the following content, for example, in a file **/plugins/acme/blog/phpunit.xml**:
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
bootstrap="../../../modules/system/tests/bootstrap/app.php"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
syntaxCheck="false"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="MyAuthor.MyPlugin Unit Test Suite">
|
||||
<directory>./tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<php>
|
||||
<env name="APP_ENV" value="testing"/>
|
||||
<env name="CACHE_DRIVER" value="array"/>
|
||||
<env name="SESSION_DRIVER" value="array"/>
|
||||
</php>
|
||||
</phpunit>
|
||||
|
||||
Then a **tests/** directory can be created to contain the test classes. The file structure should mimic the base directory with classes having a `Test` suffix. Using a namespace for the class is also recommended.
|
||||
|
||||
```php
|
||||
namespace Acme\Blog\Tests\Models;
|
||||
|
||||
use Acme\Blog\Models\Post;
|
||||
use System\Tests\Bootstrap\PluginTestCase;
|
||||
|
||||
class PostTest extends PluginTestCase
|
||||
{
|
||||
public function testCreateFirstPost()
|
||||
{
|
||||
$post = Post::create(['title' => 'Hi!']);
|
||||
$this->assertEquals(1, $post->id);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The test class should extend the base class `System\Tests\Boostrap\PluginTestCase` and this is a special class that will set up the Winter database stored in memory, as part of the `setUp` method. It will also refresh the plugin being tested, along with any of the defined dependencies in the plugin registration file. This is the equivalent of running the following before each test:
|
||||
|
||||
```bash
|
||||
php artisan winter:up
|
||||
php artisan plugin:refresh Acme.Blog
|
||||
[php artisan plugin:refresh <dependency>, ...]
|
||||
```
|
||||
|
||||
> **Note:** If your plugin uses [configuration files](../plugin/settings#file-configuration), then you will need to run `System\Classes\PluginManager::instance()->registerAll(true);` in the `setUp` method of your tests. Below is an example of a base test case class that should be used if you need to test your plugin working with other plugins instead of in isolation.
|
||||
|
||||
```php
|
||||
use System\Classes\PluginManager;
|
||||
use System\Tests\Bootstrap\PluginTestCase;
|
||||
|
||||
class BaseTestCase extends PluginTestCase
|
||||
{
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
// Get the plugin manager
|
||||
$pluginManager = PluginManager::instance();
|
||||
|
||||
// Register the plugins to make features like file configuration available
|
||||
$pluginManager->registerAll(true);
|
||||
|
||||
// Boot all the plugins to test with dependencies of this plugin
|
||||
$pluginManager->bootAll(true);
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
parent::tearDown();
|
||||
|
||||
// Get the plugin manager
|
||||
$pluginManager = PluginManager::instance();
|
||||
|
||||
// Ensure that plugins are registered again for the next test
|
||||
$pluginManager->unregisterAll();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Changing database engine for plugins tests
|
||||
|
||||
By default Winter CMS uses SQLite stored in memory for the plugin testing environment. If you want to override the default behavior you can override the `/config/database.php` file by creating `/config/testing/database.php`. In this case, variables from the latter file will be taken.
|
||||
|
||||
## Winter core modules testing
|
||||
|
||||
To perform unit testing on the core Winter modules run `artisan winter:test -m system -m backend -m cms`.
|
||||
|
||||
### Unit tests
|
||||
|
||||
Unit tests can be performed by running `vendor/bin/phpunit` in the root directory of your Winter CMS installation.
|
||||
|
||||
### Functional tests
|
||||
|
||||
Functional tests can be performed by installing the [Winter.Dusk](https://wintercms.com/plugin/winter-dusk) in your Winter CMS installation. The Winter.Dusk plugin is powered by Laravel Dusk, a comprehensive testing suite for the Laravel framework that is designed to test interactions with a fully operational Winter CMS instance through a virtual browser.
|
||||
|
||||
For information on installing and setting up your Winter CMS install to run functional tests, please review the [README](https://github.com/wintercms/wn-dusk-plugin/blob/master/README.md) for the plugin.
|
||||
28
modules/system/tests/ServiceProviderTest.php
Normal file
28
modules/system/tests/ServiceProviderTest.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests;
|
||||
|
||||
use Db;
|
||||
use Log;
|
||||
use System\Tests\Bootstrap\PluginTestCase;
|
||||
|
||||
class ServiceProviderTest extends PluginTestCase
|
||||
{
|
||||
/**
|
||||
* Test the registerLogging method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testRegisterLogging()
|
||||
{
|
||||
// Verify that calling the Log::info() method and passing in details stores those details in the event log table
|
||||
$message = 'This is a test log message';
|
||||
$details = [
|
||||
'key' => 'Dummy value',
|
||||
];
|
||||
Log::info($message, $details);
|
||||
$latestLog = Db::table('system_event_logs')->latest()->first();
|
||||
$this->assertEquals($message, $latestLog->message);
|
||||
$this->assertEquals($details, json_decode($latestLog->details, true));
|
||||
}
|
||||
}
|
||||
117
modules/system/tests/bootstrap/PluginManagerTestCase.php
Normal file
117
modules/system/tests/bootstrap/PluginManagerTestCase.php
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Bootstrap;
|
||||
|
||||
use System\Classes\UpdateManager;
|
||||
use System\Classes\VersionManager;
|
||||
use System\Classes\PluginManager;
|
||||
use ReflectionClass;
|
||||
|
||||
use Winter\Storm\Database\Model as ActiveRecord;
|
||||
|
||||
class PluginManagerTestCase extends TestCase
|
||||
{
|
||||
public ?PluginManager $manager = null;
|
||||
protected $output;
|
||||
|
||||
/**
|
||||
* Creates the application.
|
||||
* @return Symfony\Component\HttpKernel\HttpKernelInterface
|
||||
*/
|
||||
public function createApplication()
|
||||
{
|
||||
$app = parent::createApplication();
|
||||
|
||||
/*
|
||||
* Store database in memory by default unless specified otherwise
|
||||
*/
|
||||
if (!file_exists(base_path('config/testing/database.php'))) {
|
||||
$app['config']->set('database.connections.testing', [
|
||||
'driver' => 'sqlite',
|
||||
'database' => ':memory:',
|
||||
]);
|
||||
$app['config']->set('database.default', 'testing');
|
||||
}
|
||||
|
||||
return $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform test case set up.
|
||||
* @return void
|
||||
*/
|
||||
public function setUp() : void
|
||||
{
|
||||
/*
|
||||
* Force reload of Winter singletons
|
||||
*/
|
||||
PluginManager::forgetInstance();
|
||||
UpdateManager::forgetInstance();
|
||||
|
||||
// Forces plugin migrations to be run again on every test
|
||||
VersionManager::forgetInstance();
|
||||
|
||||
$this->output = new \Symfony\Component\Console\Output\BufferedOutput();
|
||||
|
||||
parent::setUp();
|
||||
|
||||
/*
|
||||
* Ensure system is up to date
|
||||
*/
|
||||
$this->runWinterUpCommand();
|
||||
|
||||
$manager = PluginManager::instance();
|
||||
self::callProtectedMethod($manager, 'init');
|
||||
$this->manager = $manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush event listeners and collect garbage.
|
||||
* @return void
|
||||
*/
|
||||
public function tearDown() : void
|
||||
{
|
||||
$this->flushModelEventListeners();
|
||||
parent::tearDown();
|
||||
unset($this->app);
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate database using winter:up command.
|
||||
* @return void
|
||||
*/
|
||||
protected function runWinterUpCommand()
|
||||
{
|
||||
UpdateManager::instance()
|
||||
->setNotesOutput($this->output)
|
||||
->update();
|
||||
}
|
||||
|
||||
/**
|
||||
* The models in Winter use a static property to store their events, these
|
||||
* will need to be targeted and reset ready for a new test cycle.
|
||||
* Pivot models are an exception since they are internally managed.
|
||||
* @return void
|
||||
*/
|
||||
protected function flushModelEventListeners()
|
||||
{
|
||||
foreach (get_declared_classes() as $class) {
|
||||
if ($class === 'Winter\Storm\Database\Pivot' || strtolower($class) === 'october\rain\database\pivot') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$reflectClass = new ReflectionClass($class);
|
||||
if (
|
||||
!$reflectClass->isInstantiable() ||
|
||||
!$reflectClass->isSubclassOf('Winter\Storm\Database\Model') ||
|
||||
$reflectClass->isSubclassOf('Winter\Storm\Database\Pivot')
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$class::flushEventListeners();
|
||||
}
|
||||
|
||||
ActiveRecord::flushEventListeners();
|
||||
}
|
||||
}
|
||||
261
modules/system/tests/bootstrap/PluginTestCase.php
Normal file
261
modules/system/tests/bootstrap/PluginTestCase.php
Normal file
@@ -0,0 +1,261 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Bootstrap;
|
||||
|
||||
use Mail;
|
||||
use Config;
|
||||
use Artisan;
|
||||
use Exception;
|
||||
use ReflectionClass;
|
||||
use Backend\Classes\AuthManager;
|
||||
use Backend\Tests\Concerns\InteractsWithAuthentication;
|
||||
use Mockery\MockInterface;
|
||||
use System\Classes\PluginBase;
|
||||
use System\Classes\PluginManager;
|
||||
use System\Classes\UpdateManager;
|
||||
use Winter\Storm\Database\Model as BaseModel;
|
||||
|
||||
/**
|
||||
* Plugin test case.
|
||||
*
|
||||
* The base test case that should be used for plugin tests. It instantiates the given plugin and
|
||||
* its dependencies, and ensures that the plugin is available for use within the tests.
|
||||
*
|
||||
* @package winter/wn-system-module
|
||||
*/
|
||||
abstract class PluginTestCase extends TestCase
|
||||
{
|
||||
use InteractsWithAuthentication;
|
||||
|
||||
/**
|
||||
* @var array Cache for storing which plugins have been loaded.
|
||||
*/
|
||||
protected $pluginTestCaseLoadedPlugins = [];
|
||||
|
||||
/**
|
||||
* Creates the application.
|
||||
*
|
||||
* @return \Symfony\Component\HttpKernel\HttpKernelInterface
|
||||
*/
|
||||
public function createApplication()
|
||||
{
|
||||
$app = require __DIR__ . '/../../../../bootstrap/app.php';
|
||||
$app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();
|
||||
|
||||
$app['cache']->setDefaultDriver('array');
|
||||
$app->setLocale('en');
|
||||
|
||||
$app->singleton('backend.auth', function ($app) {
|
||||
$app['auth.loaded'] = true;
|
||||
|
||||
return AuthManager::instance();
|
||||
});
|
||||
|
||||
// Store database in memory by default unless otherwise specified
|
||||
if (!file_exists(base_path('config/testing/database.php'))) {
|
||||
$app['config']->set('database.connections.testing', [
|
||||
'driver' => 'sqlite',
|
||||
'database' => ':memory:',
|
||||
]);
|
||||
$app['config']->set('database.default', 'testing');
|
||||
}
|
||||
|
||||
// Set random encryption key
|
||||
$app['config']->set('app.key', bin2hex(random_bytes(16)));
|
||||
|
||||
// Modify the plugin path away from the test context
|
||||
$app->setPluginsPath(realpath(base_path() . Config::get('cms.pluginsPath')));
|
||||
|
||||
return $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform test case set up.
|
||||
*/
|
||||
public function setUp(): void
|
||||
{
|
||||
// Reload the plugin and update manager singletons
|
||||
PluginManager::forgetInstance();
|
||||
UpdateManager::forgetInstance();
|
||||
|
||||
parent::setUp();
|
||||
|
||||
// Reset loaded routes
|
||||
$this->app['router']->setRoutes(new \Illuminate\Routing\RouteCollection);
|
||||
|
||||
// Run all migrations
|
||||
Artisan::call('winter:up');
|
||||
|
||||
// Reset loaded plugins for this test
|
||||
$this->pluginTestCaseLoadedPlugins = [];
|
||||
|
||||
// Detect the plugin being tested and load it automatically
|
||||
$pluginCode = $this->guessPluginCode();
|
||||
if (!is_null($pluginCode)) {
|
||||
$this->instantiatePlugin($pluginCode, false);
|
||||
}
|
||||
|
||||
// Reload module routes
|
||||
foreach (Config::get('cms.loadModules', []) as $module) {
|
||||
include base_path("modules/" . strtolower($module) . "/routes.php");
|
||||
}
|
||||
|
||||
// Disable mailing
|
||||
Mail::pretend();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush event listeners and tear down.
|
||||
*/
|
||||
public function tearDown(): void
|
||||
{
|
||||
$this->flushModelEventListeners();
|
||||
parent::tearDown();
|
||||
unset($this->app);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes a plugin for testing.
|
||||
*
|
||||
* Since the test environment has loaded all the test plugins natively, this method will ensure
|
||||
* the desired plugin is loaded in the system before proceeding to migrate it.
|
||||
*
|
||||
* @deprecated v1.2.1 Use `instantiatePlugin()` instead.
|
||||
* @return void
|
||||
*/
|
||||
protected function runPluginRefreshCommand($code, $throwException = true)
|
||||
{
|
||||
$this->instantiatePlugin((string) $code, (bool) $throwException);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a plugin for testing.
|
||||
*
|
||||
* @param string $code Plugin code.
|
||||
* @param boolean $throw Throw an exception if the plugin cannot be found.
|
||||
*/
|
||||
protected function instantiatePlugin(string $code, bool $throw = true): void
|
||||
{
|
||||
// Check plugin code is valid
|
||||
if (!preg_match('/^[\w+]*\.[\w+]*$/', $code)) {
|
||||
if (!$throw) {
|
||||
return;
|
||||
}
|
||||
throw new Exception(sprintf('Invalid plugin code: "%s"', $code));
|
||||
}
|
||||
|
||||
$manager = PluginManager::instance();
|
||||
$plugin = $manager->findByIdentifier($code);
|
||||
$firstLoad = !$plugin;
|
||||
|
||||
// First time seeing this plugin, load it up
|
||||
if ($firstLoad) {
|
||||
$namespace = '\\'.str_replace('.', '\\', $code);
|
||||
$path = array_get(
|
||||
array_change_key_case($manager->getPluginNamespaces(), CASE_LOWER),
|
||||
strtolower($namespace)
|
||||
);
|
||||
|
||||
if (!$path) {
|
||||
if (!$throw) {
|
||||
return;
|
||||
}
|
||||
throw new Exception(sprintf('Unable to find plugin with code: "%s"', $code));
|
||||
}
|
||||
|
||||
$plugin = $manager->loadPlugin($namespace, $path);
|
||||
$manager->registerPlugin($plugin);
|
||||
}
|
||||
|
||||
$this->pluginTestCaseLoadedPlugins[$code] = $plugin;
|
||||
|
||||
// Load any dependencies
|
||||
if (!empty($plugin->require)) {
|
||||
foreach ((array) $plugin->require as $dependency) {
|
||||
if (isset($this->pluginTestCaseLoadedPlugins[$dependency])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->instantiatePlugin($dependency);
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh the plugin's tables
|
||||
Artisan::call('plugin:refresh', ['plugin' => $code, '--force' => true]);
|
||||
|
||||
// Boot the plugin if this is the first load
|
||||
if ($firstLoad) {
|
||||
$manager->bootPlugin($plugin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a plugin object from its code, useful for registering events, etc.
|
||||
*/
|
||||
protected function getPluginObject($code = null): ?PluginBase
|
||||
{
|
||||
return $this->pluginTestCaseLoadedPlugins[$code]
|
||||
?? $this->pluginTestCaseLoadedPlugins[$this->guessPluginCode()]
|
||||
?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush model event listeners.
|
||||
*
|
||||
* The models in Winter use a static property to store their events. These will need to be
|
||||
* targeted and reset, ready for a new test cycle.
|
||||
*
|
||||
* Pivot models are an exception since they are internally managed.
|
||||
*/
|
||||
protected function flushModelEventListeners(): void
|
||||
{
|
||||
foreach (get_declared_classes() as $class) {
|
||||
if ($class === 'Winter\Storm\Database\Pivot' || strtolower($class) === 'october\rain\database\pivot') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$reflectClass = new ReflectionClass($class);
|
||||
if (
|
||||
!$reflectClass->isInstantiable() ||
|
||||
!$reflectClass->isSubclassOf('Winter\Storm\Database\Model') ||
|
||||
$reflectClass->isSubclassOf('Winter\Storm\Database\Pivot') ||
|
||||
in_array(MockInterface::class, $reflectClass->getInterfaceNames())
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$class::flushEventListeners();
|
||||
}
|
||||
|
||||
BaseModel::flushEventListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guesses the plugin code being tested.
|
||||
*/
|
||||
protected function guessPluginCode(): ?string
|
||||
{
|
||||
$reflect = new ReflectionClass($this);
|
||||
$fqClass = $reflect->getName();
|
||||
$namespace = $reflect->getNamespaceName();
|
||||
|
||||
if (empty($namespace)) {
|
||||
// Try to determine from the path instead
|
||||
$path = $reflect->getFilename();
|
||||
$basePath = $this->app->pluginsPath();
|
||||
|
||||
if (!strpos($path, $basePath) === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$pluginCode = ltrim(str_replace('\\', '/', substr($path, strlen($basePath))), '/');
|
||||
$pluginCode = implode('.', array_slice(explode('/', $pluginCode), 0, 2));
|
||||
} else {
|
||||
// Determine code from namespace
|
||||
$manager = PluginManager::instance();
|
||||
$pluginCode = $manager->getIdentifier($fqClass);
|
||||
}
|
||||
|
||||
return $pluginCode;
|
||||
}
|
||||
}
|
||||
94
modules/system/tests/bootstrap/TestCase.php
Normal file
94
modules/system/tests/bootstrap/TestCase.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Bootstrap;
|
||||
|
||||
use ReflectionClass;
|
||||
use PHPUnit\Framework\Assert;
|
||||
|
||||
class TestCase extends \Illuminate\Foundation\Testing\TestCase
|
||||
{
|
||||
/**
|
||||
* Creates the application.
|
||||
*
|
||||
* @return \Illuminate\Foundation\Application
|
||||
*/
|
||||
public function createApplication()
|
||||
{
|
||||
$app = require __DIR__ . '/../../../../bootstrap/app.php';
|
||||
|
||||
$app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();
|
||||
|
||||
$app['cache']->setDefaultDriver('array');
|
||||
$app->setLocale('en');
|
||||
|
||||
// Set random encryption key
|
||||
$app['config']->set('app.key', bin2hex(random_bytes(16)));
|
||||
|
||||
return $app;
|
||||
}
|
||||
|
||||
//
|
||||
// Helpers
|
||||
//
|
||||
|
||||
protected static function callProtectedMethod($object, $name, $params = [])
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$method = $class->getMethod($name);
|
||||
$method->setAccessible(true);
|
||||
return $method->invokeArgs($object, $params);
|
||||
}
|
||||
|
||||
public static function getProtectedProperty($object, $name)
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$property = $class->getProperty($name);
|
||||
$property->setAccessible(true);
|
||||
return $property->getValue($object);
|
||||
}
|
||||
|
||||
public static function setProtectedProperty($object, $name, $value)
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$property = $class->getProperty($name);
|
||||
$property->setAccessible(true);
|
||||
return $property->setValue($object, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stub for `assertFileNotExists` to allow compatibility with both PHPUnit 8 and 9.
|
||||
*
|
||||
* @param string $filename
|
||||
* @param string $message
|
||||
* @return void
|
||||
*/
|
||||
public static function assertFileNotExists(string $filename, string $message = ''): void
|
||||
{
|
||||
if (method_exists(Assert::class, 'assertFileDoesNotExist')) {
|
||||
Assert::assertFileDoesNotExist($filename, $message);
|
||||
return;
|
||||
}
|
||||
|
||||
Assert::assertFileNotExists($filename, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stub for `assertRegExp` to allow compatibility with both PHPUnit 8 and 9.
|
||||
*
|
||||
* @param string $filename
|
||||
* @param string $message
|
||||
* @return void
|
||||
*/
|
||||
public static function assertRegExp(string $pattern, string $string, string $message = ''): void
|
||||
{
|
||||
if (method_exists(Assert::class, 'assertMatchesRegularExpression')) {
|
||||
Assert::assertMatchesRegularExpression($pattern, $string, $message);
|
||||
return;
|
||||
}
|
||||
|
||||
Assert::assertRegExp($pattern, $string, $message);
|
||||
}
|
||||
}
|
||||
59
modules/system/tests/bootstrap/app.php
Normal file
59
modules/system/tests/bootstrap/app.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
$baseDir = realpath(__DIR__ . '/../../../..');
|
||||
|
||||
/*
|
||||
* Winter autoloader
|
||||
*/
|
||||
require $baseDir . '/bootstrap/autoload.php';
|
||||
|
||||
/*
|
||||
* Fallback autoloader
|
||||
*/
|
||||
$loader = new Winter\Storm\Support\ClassLoader(
|
||||
new Winter\Storm\Filesystem\Filesystem,
|
||||
$baseDir,
|
||||
$baseDir . '/storage/framework/classes.php'
|
||||
);
|
||||
|
||||
$loader->register();
|
||||
|
||||
/*
|
||||
* Manually register all module classes for autoloading
|
||||
*/
|
||||
foreach (glob($baseDir . '/modules/*', GLOB_ONLYDIR) as $modulePath) {
|
||||
$loader->autoloadPackage(basename($modulePath), $modulePath);
|
||||
}
|
||||
|
||||
/*
|
||||
* Manually register System aliases
|
||||
*/
|
||||
foreach (require(__DIR__ . '/../../aliases.php') as $alias => $class) {
|
||||
if (!class_exists($alias)) {
|
||||
class_alias($class, $alias);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Manually register all plugin classes for autoloading
|
||||
*/
|
||||
$dirPath = $baseDir . '/plugins';
|
||||
if (is_dir($dirPath)) {
|
||||
$it = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator($dirPath, FilesystemIterator::FOLLOW_SYMLINKS)
|
||||
);
|
||||
$it->setMaxDepth(2);
|
||||
$it->rewind();
|
||||
|
||||
while ($it->valid()) {
|
||||
if (($it->getDepth() > 1) && $it->isFile() && (strtolower($it->getFilename()) === "plugin.php")) {
|
||||
$filePath = dirname($it->getPathname());
|
||||
$pluginName = basename($filePath);
|
||||
$vendorName = basename(dirname($filePath));
|
||||
|
||||
$loader->autoloadPackage($vendorName . '\\' . $pluginName, $filePath);
|
||||
}
|
||||
|
||||
$it->next();
|
||||
}
|
||||
}
|
||||
297
modules/system/tests/classes/CombineAssetsTest.php
Normal file
297
modules/system/tests/classes/CombineAssetsTest.php
Normal file
@@ -0,0 +1,297 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Classes;
|
||||
|
||||
use System\Tests\Bootstrap\TestCase;
|
||||
use Cms\Classes\Theme;
|
||||
use System\Classes\CombineAssets;
|
||||
|
||||
class CombineAssetsTest extends TestCase
|
||||
{
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
CombineAssets::resetCache();
|
||||
}
|
||||
|
||||
//
|
||||
// Tests
|
||||
//
|
||||
|
||||
public function testCombiner()
|
||||
{
|
||||
$combiner = CombineAssets::instance();
|
||||
|
||||
/*
|
||||
* Supported file extensions should exist
|
||||
*/
|
||||
$jsExt = $cssExt = self::getProtectedProperty($combiner, 'jsExtensions');
|
||||
$this->assertIsArray($jsExt);
|
||||
|
||||
$cssExt = self::getProtectedProperty($combiner, 'cssExtensions');
|
||||
$this->assertIsArray($cssExt);
|
||||
|
||||
/*
|
||||
* Check service methods
|
||||
*/
|
||||
$this->assertTrue(method_exists($combiner, 'combine'));
|
||||
$this->assertTrue(method_exists($combiner, 'resetCache'));
|
||||
}
|
||||
|
||||
public function testCombine()
|
||||
{
|
||||
$combiner = CombineAssets::instance();
|
||||
|
||||
$url = $combiner->combine(
|
||||
[
|
||||
'assets/css/style1.css',
|
||||
'assets/css/style2.css'
|
||||
],
|
||||
base_path() . '/modules/system/tests/fixtures/themes/test'
|
||||
);
|
||||
$this->assertNotNull($url);
|
||||
$this->assertRegExp('/\w+[-]\d+/i', $url); // Must contain hash-number
|
||||
|
||||
$url = $combiner->combine(
|
||||
[
|
||||
'assets/js/script1.js',
|
||||
'assets/js/script2.js'
|
||||
],
|
||||
base_path() . '/modules/system/tests/fixtures/themes/test'
|
||||
);
|
||||
$this->assertNotNull($url);
|
||||
$this->assertRegExp('/\w+[-]\d+/i', $url); // Must contain hash-number
|
||||
}
|
||||
|
||||
public function testPutCache()
|
||||
{
|
||||
$sampleId = md5('testhash');
|
||||
$sampleStore = ['version' => 12345678];
|
||||
$samplePath = '/tests/fixtures/Cms/themes/test';
|
||||
|
||||
$combiner = CombineAssets::instance();
|
||||
$value = self::callProtectedMethod($combiner, 'putCache', [$sampleId, $sampleStore]);
|
||||
|
||||
$this->assertTrue($value);
|
||||
}
|
||||
|
||||
public function testGetTargetPath()
|
||||
{
|
||||
$combiner = CombineAssets::instance();
|
||||
|
||||
$value = self::callProtectedMethod($combiner, 'getTargetPath', ['/combine']);
|
||||
$this->assertEquals('combine/', $value);
|
||||
|
||||
$value = self::callProtectedMethod($combiner, 'getTargetPath', ['/index.php/combine']);
|
||||
$this->assertEquals('index-php/combine/', $value);
|
||||
}
|
||||
|
||||
public function testMakeCacheId()
|
||||
{
|
||||
$sampleResources = ['assets/css/style1.css', 'assets/css/style2.css'];
|
||||
$samplePath = base_path() . '/modules/system/tests/fixtures/cms/themes/test';
|
||||
|
||||
$combiner = CombineAssets::instance();
|
||||
self::setProtectedProperty($combiner, 'localPath', $samplePath);
|
||||
|
||||
$value = self::callProtectedMethod($combiner, 'getCacheKey', [$sampleResources]);
|
||||
$this->assertEquals(md5($samplePath.implode('|', $sampleResources)), $value);
|
||||
}
|
||||
|
||||
public function testResetCache()
|
||||
{
|
||||
$combiner = CombineAssets::instance();
|
||||
$this->assertNull($combiner->resetCache());
|
||||
}
|
||||
|
||||
/**
|
||||
* Regression for GHSA-58fp-mcx6-7qf9. A writable theme `.less` file containing
|
||||
* `@import (inline) "<absolute-path>"` must not disclose server files.
|
||||
*/
|
||||
public function testLessCompilerBlocksAbsolutePathImport()
|
||||
{
|
||||
[$themeDir, $secretPath] = $this->setupLessLeakFixture(
|
||||
'@import (inline) "%SECRET%"; .x { color: red; }'
|
||||
);
|
||||
|
||||
try {
|
||||
$css = $this->compileLessTo($themeDir, 'assets/less/poc.less');
|
||||
$this->assertStringNotContainsString('APP_KEY', $css);
|
||||
$this->assertStringNotContainsString('combine-leak-canary', $css);
|
||||
} finally {
|
||||
$this->teardownLessLeakFixture($themeDir, $secretPath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Regression for the relative-traversal path of GHSA-58fp-mcx6-7qf9. less.php's
|
||||
* auto-added `currentDirectory` import_dir entry resolves `..` traversal
|
||||
* natively; without the key-collision override in LessImportResolver, a theme
|
||||
* `.less` could still escape via `@import (inline) "../../../etc/passwd"`.
|
||||
*/
|
||||
public function testLessCompilerBlocksRelativeTraversalImport()
|
||||
{
|
||||
// From themeDir/assets/less/poc.less, traverse up enough to escape the
|
||||
// theme tree, the themes root, and out to the secret file the fixture
|
||||
// wrote at sys_get_temp_dir().
|
||||
[$themeDir, $secretPath] = $this->setupLessLeakFixture(
|
||||
'@import (inline) "' . str_repeat('../', 20) . ltrim($this->lastSecretPath, '/') . '"; .x { color: red; }'
|
||||
);
|
||||
|
||||
try {
|
||||
$css = $this->compileLessTo($themeDir, 'assets/less/poc.less');
|
||||
$this->assertStringNotContainsString('APP_KEY', $css);
|
||||
$this->assertStringNotContainsString('combine-leak-canary', $css);
|
||||
} finally {
|
||||
$this->teardownLessLeakFixture($themeDir, $secretPath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Legitimate same-tree `@import "partial.less"` must still resolve through
|
||||
* the gate, otherwise we've broken every theme that uses partials.
|
||||
*/
|
||||
public function testLessCompilerAllowsLegitimatePartial()
|
||||
{
|
||||
$themeDir = $this->makeTempThemeDir();
|
||||
$mainPath = $themeDir . '/assets/less/main.less';
|
||||
$partialPath = $themeDir . '/assets/less/partial.less';
|
||||
file_put_contents($partialPath, '.partial-marker { color: orange; }');
|
||||
file_put_contents($mainPath, '@import "partial.less"; .main-marker { color: blue; }');
|
||||
|
||||
try {
|
||||
$css = $this->compileLessTo($themeDir, 'assets/less/main.less');
|
||||
$this->assertStringContainsString('partial-marker', $css);
|
||||
$this->assertStringContainsString('main-marker', $css);
|
||||
} finally {
|
||||
\File::deleteDirectory($themeDir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Regression for GHSA-2223-f22x-24cq. A writable theme `.js` asset containing
|
||||
* `=include ../../../.env` must not disclose server files through the combiner,
|
||||
* whose output is served unauthenticated via the `combine/{file}` route.
|
||||
*/
|
||||
public function testJavascriptImporterBlocksTraversalImport()
|
||||
{
|
||||
$themeDir = $this->makeTempThemeDir();
|
||||
// A real `.js` secret outside the theme subtree (but under base_path so
|
||||
// Assetic's FileAsset root check passes). It escapes via `..` traversal but
|
||||
// lands outside every allowed import root, so it must not be inlined.
|
||||
$secretPath = dirname($themeDir) . '/js-secret-' . bin2hex(random_bytes(4)) . '.js';
|
||||
file_put_contents($secretPath, 'var LEAK = "combine-leak-canary";');
|
||||
file_put_contents(
|
||||
$themeDir . '/assets/poc.js',
|
||||
"/*\n=include ../../" . basename($secretPath) . "\n*/\n"
|
||||
);
|
||||
|
||||
try {
|
||||
$js = $this->compileJsTo($themeDir, 'assets/poc.js');
|
||||
$this->assertStringNotContainsString('combine-leak-canary', $js);
|
||||
} finally {
|
||||
@unlink($secretPath);
|
||||
\File::deleteDirectory($themeDir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `.js`-only extension gate must block disclosure of non-JS files (e.g.
|
||||
* `.env`) before any path resolution, even inside an otherwise reachable tree.
|
||||
*/
|
||||
public function testJavascriptImporterBlocksDisallowedExtension()
|
||||
{
|
||||
$themeDir = $this->makeTempThemeDir();
|
||||
$secretPath = dirname($themeDir) . '/js-secret-' . bin2hex(random_bytes(4)) . '.env';
|
||||
file_put_contents($secretPath, "APP_KEY=combine-leak-canary\n");
|
||||
file_put_contents(
|
||||
$themeDir . '/assets/poc.js',
|
||||
"/*\n=include ../../" . basename($secretPath) . "\n*/\n"
|
||||
);
|
||||
|
||||
try {
|
||||
$js = $this->compileJsTo($themeDir, 'assets/poc.js');
|
||||
$this->assertStringNotContainsString('combine-leak-canary', $js);
|
||||
} finally {
|
||||
@unlink($secretPath);
|
||||
\File::deleteDirectory($themeDir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Legitimate same-tree `=include partial.js` must still resolve, otherwise the
|
||||
* hardening would break every asset that composes its own bundle.
|
||||
*/
|
||||
public function testJavascriptImporterAllowsSameTreeInclude()
|
||||
{
|
||||
$themeDir = $this->makeTempThemeDir();
|
||||
file_put_contents($themeDir . '/assets/partial.js', 'var PARTIAL = "partial-marker";');
|
||||
file_put_contents($themeDir . '/assets/main.js', "/*\n=include partial.js\n*/\nvar MAIN = 1;");
|
||||
|
||||
try {
|
||||
$js = $this->compileJsTo($themeDir, 'assets/main.js');
|
||||
$this->assertStringContainsString('partial-marker', $js);
|
||||
} finally {
|
||||
\File::deleteDirectory($themeDir);
|
||||
}
|
||||
}
|
||||
|
||||
protected function compileJsTo(string $themeDir, string $relativeAsset): string
|
||||
{
|
||||
$dest = sys_get_temp_dir() . '/winter-combine-out-' . bin2hex(random_bytes(4)) . '.js';
|
||||
try {
|
||||
CombineAssets::instance()->combineToFile([$relativeAsset], $dest, $themeDir);
|
||||
return file_get_contents($dest) ?: '';
|
||||
} finally {
|
||||
@unlink($dest);
|
||||
}
|
||||
}
|
||||
|
||||
/** @var string */
|
||||
protected $lastSecretPath = '';
|
||||
|
||||
/**
|
||||
* @return array{0:string,1:string} [theme dir, secret path]
|
||||
*/
|
||||
protected function setupLessLeakFixture(string $pocTemplate): array
|
||||
{
|
||||
$themeDir = $this->makeTempThemeDir();
|
||||
$secretPath = tempnam(sys_get_temp_dir(), 'combine-leak-canary-');
|
||||
file_put_contents($secretPath, "APP_KEY=do-not-leak-via-combiner\n");
|
||||
$this->lastSecretPath = $secretPath;
|
||||
|
||||
$poc = str_replace('%SECRET%', $secretPath, $pocTemplate);
|
||||
file_put_contents($themeDir . '/assets/less/poc.less', $poc);
|
||||
|
||||
return [$themeDir, $secretPath];
|
||||
}
|
||||
|
||||
protected function teardownLessLeakFixture(string $themeDir, string $secretPath): void
|
||||
{
|
||||
@unlink($secretPath);
|
||||
\File::deleteDirectory($themeDir);
|
||||
}
|
||||
|
||||
protected function makeTempThemeDir(): string
|
||||
{
|
||||
// Must live under base_path() because Assetic's FileAsset enforces that
|
||||
// the source be within the configured root, which CombineAssets sets to
|
||||
// public_path() (equal to base_path() in this install). Using sys_get_temp_dir()
|
||||
// would trigger "source is not in the root directory" errors.
|
||||
$themeDir = base_path('storage/framework/cache/security-tests/theme-' . bin2hex(random_bytes(4)));
|
||||
mkdir($themeDir . '/assets/less', 0777, true);
|
||||
return $themeDir;
|
||||
}
|
||||
|
||||
protected function compileLessTo(string $themeDir, string $relativeAsset): string
|
||||
{
|
||||
$dest = sys_get_temp_dir() . '/winter-combine-out-' . bin2hex(random_bytes(4)) . '.css';
|
||||
try {
|
||||
CombineAssets::instance()->combineToFile([$relativeAsset], $dest, $themeDir);
|
||||
return file_get_contents($dest) ?: '';
|
||||
} finally {
|
||||
@unlink($dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
52
modules/system/tests/classes/CoreLangTest.php
Normal file
52
modules/system/tests/classes/CoreLangTest.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Classes;
|
||||
|
||||
use System\Tests\Bootstrap\TestCase;
|
||||
use System\Classes\PluginManager;
|
||||
use Validator;
|
||||
|
||||
class CoreLangTest extends TestCase
|
||||
{
|
||||
public function testValidationTranslator()
|
||||
{
|
||||
$translator = $this->app['translator'];
|
||||
$translator->setLocale('en');
|
||||
|
||||
$validator = Validator::make(
|
||||
['name' => 'me'],
|
||||
['name' => 'required|min:5']
|
||||
);
|
||||
|
||||
$this->assertTrue($validator->fails());
|
||||
|
||||
$messages = $validator->messages();
|
||||
$this->assertCount(1, $messages);
|
||||
$this->assertEquals('The name must be at least 5 characters.', $messages->all()[0]);
|
||||
}
|
||||
|
||||
public function testValidCoreLanguageFiles()
|
||||
{
|
||||
$translator = $this->app['translator'];
|
||||
$locales = $translator->get('system::lang.locale');
|
||||
$this->assertNotEmpty($locales);
|
||||
|
||||
$locales = array_keys($locales);
|
||||
$modules = ['system', 'backend', 'cms'];
|
||||
$files = ['lang.php', 'validation.php', 'client.php'];
|
||||
|
||||
foreach ($modules as $module) {
|
||||
foreach ($locales as $locale) {
|
||||
foreach ($files as $file) {
|
||||
$srcPath = base_path() . '/modules/'.$module.'/lang/'.$locale.'/'.$file;
|
||||
if (!file_exists($srcPath)) {
|
||||
continue;
|
||||
}
|
||||
$messages = require $srcPath;
|
||||
$this->assertNotEmpty($messages);
|
||||
$this->assertNotCount(0, $messages);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
78
modules/system/tests/classes/FileManifestTest.php
Normal file
78
modules/system/tests/classes/FileManifestTest.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Classes;
|
||||
|
||||
use ReflectionClass;
|
||||
|
||||
use System\Tests\Bootstrap\TestCase;
|
||||
use Winter\Storm\Exception\ApplicationException;
|
||||
use System\Classes\FileManifest;
|
||||
|
||||
class FileManifestTest extends TestCase
|
||||
{
|
||||
/** @var FileManifest instance */
|
||||
protected $fileManifest;
|
||||
|
||||
/** @var root path */
|
||||
protected $root;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->root = base_path('modules/system/tests/fixtures/manifest/1_0_1');
|
||||
$this->fileManifest = new FileManifest($this->root, ['test', 'test2']);
|
||||
}
|
||||
|
||||
public function testGetFiles()
|
||||
{
|
||||
$this->assertEquals([
|
||||
'/modules/test/file1.php' => '6f9b0b94528a85b2a6bb67b5621e074aef1b4c9fc9ee3ea1bd69100ea14cb3db',
|
||||
'/modules/test/file2.php' => '96ae9f6b6377ad29226ea169f952de49fc29ae895f18a2caed76aeabdf050f1b',
|
||||
'/modules/test2/file1.php' => '94bd47b1ac7b2837b31883ebcd38c8101687321f497c3c4b9744f68ae846721d',
|
||||
], $this->fileManifest->getFiles());
|
||||
}
|
||||
|
||||
public function testGetModuleChecksums()
|
||||
{
|
||||
$this->assertEquals([
|
||||
'test' => 'c0b794ff210862a4ce16223802efe6e28969f5a4fb42480ec8c2fef2da23d181',
|
||||
'test2' => '32c9f2fb6e0a22dde288a0fe1e4834798360b25e5a91d2597409d9302221381d',
|
||||
], $this->fileManifest->getModuleChecksums());
|
||||
}
|
||||
|
||||
public function testGetFilesInvalidRoot()
|
||||
{
|
||||
$this->expectException(ApplicationException::class);
|
||||
$this->expectExceptionMessage('Invalid root specified for the file manifest.');
|
||||
|
||||
$this->fileManifest->setRoot(base_path('tests/fixtures/manifest/invalid'));
|
||||
|
||||
$this->fileManifest->getFiles();
|
||||
}
|
||||
|
||||
public function testSingleModule()
|
||||
{
|
||||
$this->fileManifest->setModules(['test']);
|
||||
|
||||
$this->assertEquals([
|
||||
'/modules/test/file1.php' => '6f9b0b94528a85b2a6bb67b5621e074aef1b4c9fc9ee3ea1bd69100ea14cb3db',
|
||||
'/modules/test/file2.php' => '96ae9f6b6377ad29226ea169f952de49fc29ae895f18a2caed76aeabdf050f1b',
|
||||
], $this->fileManifest->getFiles());
|
||||
|
||||
$this->assertEquals([
|
||||
'test' => 'c0b794ff210862a4ce16223802efe6e28969f5a4fb42480ec8c2fef2da23d181',
|
||||
], $this->fileManifest->getModuleChecksums());
|
||||
}
|
||||
|
||||
public function testGetFilename()
|
||||
{
|
||||
$class = new ReflectionClass('System\Classes\FileManifest');
|
||||
$method = $class->getMethod('getFilename');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$filename = '/modules/test/file1.php';
|
||||
|
||||
$this->assertEquals($filename, $method->invoke($this->fileManifest, $this->root . $filename));
|
||||
}
|
||||
}
|
||||
482
modules/system/tests/classes/ImageResizerTest.php
Normal file
482
modules/system/tests/classes/ImageResizerTest.php
Normal file
@@ -0,0 +1,482 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Classes;
|
||||
|
||||
use Backend\Facades\Backend;
|
||||
use Cms\Classes\Controller as CmsController;
|
||||
use Cms\Classes\Theme;
|
||||
use Config;
|
||||
use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts;
|
||||
use Event;
|
||||
use Storage;
|
||||
use System\Classes\ImageResizer;
|
||||
use System\Classes\MediaLibrary;
|
||||
use System\Models\File as FileModel;
|
||||
use System\Tests\Bootstrap\PluginTestCase;
|
||||
use URL;
|
||||
use Winter\Storm\Exception\SystemException;
|
||||
|
||||
class ImageResizerTest extends PluginTestCase
|
||||
{
|
||||
use ArraySubsetAsserts;
|
||||
|
||||
protected $originalThemesPath = '';
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->originalThemesPath = Config::get('cms.themesPath');
|
||||
Config::set('cms.themesPath', '/modules/system/tests/fixtures/themes');
|
||||
|
||||
Config::set('cms.activeTheme', 'test');
|
||||
Event::flush('cms.theme.getActiveTheme');
|
||||
Theme::resetCache();
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
$this->removeMedia();
|
||||
|
||||
Config::set('cms.themesPath', $this->originalThemesPath);
|
||||
|
||||
ImageResizer::flushAvailableSources();
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests configuration through the constructor as well as events.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testConfiguration()
|
||||
{
|
||||
if (!in_array('Cms', Config::get('cms.loadModules', []))) {
|
||||
$this->markTestSkipped('The CMS module is not active.');
|
||||
}
|
||||
|
||||
// Resize with default options
|
||||
$imageResizer = new ImageResizer(
|
||||
(new CmsController())->themeUrl('assets/images/winter.png'),
|
||||
100,
|
||||
100
|
||||
);
|
||||
self::assertArraySubset([
|
||||
'width' => 100,
|
||||
'height' => 100,
|
||||
'options' => [
|
||||
'mode' => 'auto',
|
||||
'offset' => [0, 0],
|
||||
'sharpen' => 0,
|
||||
'interlace' => false,
|
||||
'quality' => 90,
|
||||
'extension' => 'png',
|
||||
],
|
||||
], $imageResizer->getConfig());
|
||||
|
||||
// Resize with customised options
|
||||
$imageResizer = new ImageResizer(
|
||||
(new CmsController())->themeUrl('assets/images/winter.png'),
|
||||
150,
|
||||
120,
|
||||
[
|
||||
'mode' => 'fit',
|
||||
'offset' => [2, 2],
|
||||
'sharpen' => 23,
|
||||
'interlace' => true,
|
||||
'quality' => 73,
|
||||
'extension' => 'jpg'
|
||||
]
|
||||
);
|
||||
self::assertArraySubset([
|
||||
'width' => 150,
|
||||
'height' => 120,
|
||||
'options' => [
|
||||
'mode' => 'fit',
|
||||
'offset' => [2, 2],
|
||||
'sharpen' => 23,
|
||||
'interlace' => true,
|
||||
'quality' => 73,
|
||||
'extension' => 'jpg'
|
||||
],
|
||||
], $imageResizer->getConfig());
|
||||
|
||||
// Resize with an customised defaults
|
||||
Event::listen('system.resizer.getDefaultOptions', function (&$options) {
|
||||
$options = array_merge($options, [
|
||||
'mode' => 'fit',
|
||||
'offset' => [2, 2],
|
||||
'sharpen' => 23,
|
||||
'interlace' => true,
|
||||
'quality' => 73,
|
||||
]);
|
||||
});
|
||||
|
||||
$imageResizer = new ImageResizer(
|
||||
(new CmsController())->themeUrl('assets/images/winter.png'),
|
||||
100,
|
||||
100,
|
||||
[]
|
||||
);
|
||||
self::assertArraySubset([
|
||||
'width' => 100,
|
||||
'height' => 100,
|
||||
'options' => [
|
||||
'mode' => 'fit',
|
||||
'offset' => [2, 2],
|
||||
'sharpen' => 23,
|
||||
'interlace' => true,
|
||||
'quality' => 73,
|
||||
'extension' => 'png',
|
||||
],
|
||||
], $imageResizer->getConfig());
|
||||
|
||||
Event::forget('system.resizer.getDefaultOptions');
|
||||
|
||||
// Resize with a falsey height specified
|
||||
$imageResizer = new ImageResizer(
|
||||
(new CmsController())->themeUrl('assets/images/winter.png'),
|
||||
100,
|
||||
false
|
||||
);
|
||||
self::assertArraySubset([
|
||||
'width' => 100,
|
||||
'height' => 0,
|
||||
], $imageResizer->getConfig());
|
||||
|
||||
$imageResizer = new ImageResizer(
|
||||
(new CmsController())->themeUrl('assets/images/winter.png'),
|
||||
100,
|
||||
null
|
||||
);
|
||||
self::assertArraySubset([
|
||||
'width' => 100,
|
||||
'height' => 0,
|
||||
], $imageResizer->getConfig());
|
||||
|
||||
// Resize with a falsey width specified
|
||||
$imageResizer = new ImageResizer(
|
||||
(new CmsController())->themeUrl('assets/images/winter.png'),
|
||||
'',
|
||||
100
|
||||
);
|
||||
self::assertArraySubset([
|
||||
'width' => 0,
|
||||
'height' => 100,
|
||||
], $imageResizer->getConfig());
|
||||
|
||||
$imageResizer = new ImageResizer(
|
||||
(new CmsController())->themeUrl('assets/images/winter.png'),
|
||||
"0",
|
||||
100
|
||||
);
|
||||
self::assertArraySubset([
|
||||
'width' => 0,
|
||||
'height' => 100,
|
||||
], $imageResizer->getConfig());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests URLs for sources that can be accessed via URL.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testURLSources()
|
||||
{
|
||||
if (!in_array('Cms', Config::get('cms.loadModules', []))) {
|
||||
$this->markTestSkipped('The CMS module is not active.');
|
||||
}
|
||||
|
||||
// Theme URL (absolute URL)
|
||||
$this->setUpStorage();
|
||||
$this->copyMedia();
|
||||
|
||||
$imageResizer = new ImageResizer(
|
||||
(new CmsController())->themeUrl('assets/images/winter.png'),
|
||||
100,
|
||||
100
|
||||
);
|
||||
$this->assertEquals('png', $imageResizer->getConfig()['options']['extension']);
|
||||
|
||||
// Theme URL (relative URL)
|
||||
$this->setUpStorage();
|
||||
$this->copyMedia();
|
||||
|
||||
$imageResizer = new ImageResizer(
|
||||
'/modules/system/tests/fixtures/themes/test/assets/images/winter.png',
|
||||
100,
|
||||
100
|
||||
);
|
||||
$this->assertEquals('png', $imageResizer->getConfig()['options']['extension']);
|
||||
|
||||
// Media URL (absolute URL)
|
||||
$this->setUpStorage();
|
||||
$this->copyMedia();
|
||||
|
||||
$imageResizer = new ImageResizer(
|
||||
URL::to(MediaLibrary::url('winter.png')),
|
||||
100,
|
||||
100
|
||||
);
|
||||
$this->assertEquals('png', $imageResizer->getConfig()['options']['extension']);
|
||||
|
||||
// Media URL (relative URL)
|
||||
$this->setUpStorage();
|
||||
$this->copyMedia();
|
||||
|
||||
$imageResizer = new ImageResizer(
|
||||
MediaLibrary::url('winter.png'),
|
||||
100,
|
||||
100
|
||||
);
|
||||
$this->assertEquals('png', $imageResizer->getConfig()['options']['extension']);
|
||||
|
||||
// Media URL (absolute URL)
|
||||
$this->setUpStorage();
|
||||
$this->copyMedia();
|
||||
|
||||
$imageResizer = new ImageResizer(
|
||||
URL::to(MediaLibrary::url('winter.png')),
|
||||
100,
|
||||
100
|
||||
);
|
||||
$this->assertEquals('png', $imageResizer->getConfig()['options']['extension']);
|
||||
|
||||
// Plugin URL (relative URL)
|
||||
$imageResizer = new ImageResizer(
|
||||
'/modules/system/tests/fixtures/plugins/database/tester/assets/images/avatar.png',
|
||||
100,
|
||||
100
|
||||
);
|
||||
$this->assertEquals('png', $imageResizer->getConfig()['options']['extension']);
|
||||
|
||||
// Plugin URL (absolute URL)
|
||||
$imageResizer = new ImageResizer(
|
||||
URL::to('modules/system/tests/fixtures/plugins/database/tester/assets/images/avatar.png'),
|
||||
100,
|
||||
100
|
||||
);
|
||||
$this->assertEquals('png', $imageResizer->getConfig()['options']['extension']);
|
||||
|
||||
// Module URL (relative URL)
|
||||
$imageResizer = new ImageResizer(
|
||||
'/modules/backend/assets/images/favicon.png',
|
||||
100,
|
||||
100
|
||||
);
|
||||
$this->assertEquals('png', $imageResizer->getConfig()['options']['extension']);
|
||||
|
||||
// Module URL (absolute URL)
|
||||
$imageResizer = new ImageResizer(
|
||||
Backend::skinAsset('assets/images/favicon.png'),
|
||||
100,
|
||||
100
|
||||
);
|
||||
$this->assertEquals('png', $imageResizer->getConfig()['options']['extension']);
|
||||
|
||||
// URL for a FileModel instance (absolute URL)
|
||||
$fileModel = new FileModel();
|
||||
$fileModel->fromFile(base_path('modules/system/tests/fixtures/plugins/database/tester/assets/images/avatar.png'));
|
||||
$fileModel->save();
|
||||
|
||||
$imageResizer = new ImageResizer(
|
||||
FileModel::first()->getPath(),
|
||||
100,
|
||||
100
|
||||
);
|
||||
$this->assertEquals('png', $imageResizer->getConfig()['options']['extension']);
|
||||
|
||||
// Remove FileModel instance
|
||||
$fileModel->delete();
|
||||
|
||||
// URL of a FileModel instance (relative URL)
|
||||
$fileModel = new FileModel();
|
||||
$fileModel->fromFile(base_path('modules/system/tests/fixtures/plugins/database/tester/assets/images/avatar.png'));
|
||||
$fileModel->save();
|
||||
|
||||
$imageResizer = new ImageResizer(
|
||||
str_replace(url('') . '/', '/', FileModel::first()->getPath()),
|
||||
100,
|
||||
100
|
||||
);
|
||||
$this->assertEquals('png', $imageResizer->getConfig()['options']['extension']);
|
||||
}
|
||||
|
||||
public function testDirectSources()
|
||||
{
|
||||
// FileModel instance itself
|
||||
$fileModel = new FileModel();
|
||||
$fileModel->fromFile(base_path('modules/system/tests/fixtures/plugins/database/tester/assets/images/avatar.png'));
|
||||
$fileModel->save();
|
||||
|
||||
$imageResizer = new ImageResizer(
|
||||
$fileModel,
|
||||
100,
|
||||
100
|
||||
);
|
||||
$this->assertEquals('png', $imageResizer->getConfig()['options']['extension']);
|
||||
|
||||
// Remove FileModel instance
|
||||
$fileModel->delete();
|
||||
}
|
||||
|
||||
public function testInvalidInputPath()
|
||||
{
|
||||
$this->expectException(SystemException::class);
|
||||
$this->expectExceptionMessageMatches('/^Unable to process the provided image/');
|
||||
|
||||
$imageResizer = new ImageResizer(
|
||||
'/plugins/database/tester/assets/images/MISSING.png',
|
||||
100,
|
||||
100
|
||||
);
|
||||
}
|
||||
|
||||
public function testInvalidInputFileModel()
|
||||
{
|
||||
$this->expectException(SystemException::class);
|
||||
$this->expectExceptionMessageMatches('/^Unable to process the provided image/');
|
||||
|
||||
$imageResizer = new ImageResizer(
|
||||
FileModel::first(),
|
||||
100,
|
||||
100
|
||||
);
|
||||
}
|
||||
|
||||
public function testSpaceInFilename()
|
||||
{
|
||||
// Media URL with space
|
||||
$this->setUpStorage();
|
||||
$this->copyMedia();
|
||||
|
||||
$imageResizer = new ImageResizer(
|
||||
URL::to(MediaLibrary::url('winter space.png')),
|
||||
100,
|
||||
100
|
||||
);
|
||||
|
||||
$this->assertStringContainsString('winter%20space', $imageResizer->getResizedUrl(), 'Resized URLs are not properly URL encoded');
|
||||
}
|
||||
|
||||
public function testGetResizedUrl()
|
||||
{
|
||||
if (!in_array('Cms', Config::get('cms.loadModules', []))) {
|
||||
$this->markTestSkipped('The CMS module is not active.');
|
||||
}
|
||||
|
||||
$imageResizer = new ImageResizer((new CmsController())->themeUrl('assets/images/winter.png'));
|
||||
|
||||
Config::set('cms.linkPolicy', 'force');
|
||||
$url = $imageResizer->getResizedUrl();
|
||||
$this->assertTrue(starts_with($url, 'http'));
|
||||
|
||||
Config::set('cms.linkPolicy', 'detect');
|
||||
$url = $imageResizer->getResizedUrl();
|
||||
$this->assertTrue(starts_with($url, Config::get('cms.storage.resized.path', '/storage/tests/app/resized')));
|
||||
}
|
||||
|
||||
public function testGetResizerUrl()
|
||||
{
|
||||
if (!in_array('Cms', Config::get('cms.loadModules', []))) {
|
||||
$this->markTestSkipped('The CMS module is not active.');
|
||||
}
|
||||
|
||||
$imageResizer = new ImageResizer((new CmsController())->themeUrl('assets/images/winter.png'));
|
||||
|
||||
Config::set('cms.linkPolicy', 'force');
|
||||
$url = $imageResizer->getResizerUrl();
|
||||
$this->assertTrue(starts_with($url, 'http'));
|
||||
|
||||
Config::set('cms.linkPolicy', 'detect');
|
||||
$url = $imageResizer->getResizerUrl();
|
||||
$this->assertTrue(starts_with($url, '/resizer/'));
|
||||
|
||||
// test dots' double-encoding
|
||||
// @see https://github.com/wintercms/winter/pull/1493
|
||||
$this->assertTrue(ends_with($url, '%252Epng'));
|
||||
|
||||
// Verify the encoded URL round-trips through the resizer route's decoding and
|
||||
// signature verification. A fresh instance is required as the identifier is
|
||||
// cached on first generation and the link policy has changed since then. The
|
||||
// router decodes the parameter once before it reaches getValidResizedUrl().
|
||||
$imageResizer = new ImageResizer((new CmsController())->themeUrl('assets/images/winter.png'));
|
||||
[$identifier, $encodedUrl] = array_slice(explode('/', $imageResizer->getResizerUrl()), 2);
|
||||
$this->assertSame(
|
||||
$imageResizer->getResizedUrl(),
|
||||
ImageResizer::getValidResizedUrl($identifier, rawurldecode($encodedUrl))
|
||||
);
|
||||
}
|
||||
|
||||
public function testResizerRedirect()
|
||||
{
|
||||
if (!in_array('Cms', Config::get('cms.loadModules', []))) {
|
||||
$this->markTestSkipped('The CMS module is not active.');
|
||||
}
|
||||
|
||||
$this->setUpStorage();
|
||||
$this->copyMedia();
|
||||
Config::set('cms.storage.resized', [
|
||||
'disk' => 'test_local',
|
||||
'folder' => 'resized',
|
||||
'path' => '/storage/temp/app/resized',
|
||||
]);
|
||||
|
||||
$imageResizer = new ImageResizer((new CmsController())->themeUrl('assets/images/winter.png'), 50, 50);
|
||||
|
||||
// The resizer route responds with a permanent redirect as a resizer URL can
|
||||
// only ever target the resized URL embedded and signed within it, and this
|
||||
// also exercises the full round-trip of the double-encoded URL parameter
|
||||
// through the actual router
|
||||
$response = $this->get($imageResizer->getResizerUrl());
|
||||
$response->assertStatus(301);
|
||||
$response->assertRedirect($imageResizer->getResizedUrl());
|
||||
|
||||
// Clean up the generated image
|
||||
Storage::disk('test_local')->deleteDirectory('resized');
|
||||
}
|
||||
|
||||
protected function setUpStorage()
|
||||
{
|
||||
$this->app->useStoragePath(base_path('storage/temp'));
|
||||
|
||||
Config::set('filesystems.disks.test_local', [
|
||||
'driver' => 'local',
|
||||
'root' => storage_path('app'),
|
||||
]);
|
||||
|
||||
Config::set('cms.storage.media', [
|
||||
'disk' => 'test_local',
|
||||
'folder' => 'media',
|
||||
'path' => '/storage/temp/app/media',
|
||||
]);
|
||||
}
|
||||
|
||||
protected function copyMedia()
|
||||
{
|
||||
$mediaPath = storage_path('app/media');
|
||||
|
||||
if (!is_dir($mediaPath)) {
|
||||
mkdir($mediaPath, 0777, true);
|
||||
}
|
||||
|
||||
foreach (glob(base_path('modules/system/tests/fixtures/media/*')) as $file) {
|
||||
$path = pathinfo($file);
|
||||
copy($file, $mediaPath . DIRECTORY_SEPARATOR . $path['basename']);
|
||||
}
|
||||
}
|
||||
|
||||
protected function removeMedia()
|
||||
{
|
||||
if ($this->app->storagePath() !== base_path('storage/temp')) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (glob(storage_path('app/media/*')) as $file) {
|
||||
unlink($file);
|
||||
}
|
||||
|
||||
rmdir(storage_path('app/media'));
|
||||
rmdir(storage_path('app'));
|
||||
}
|
||||
}
|
||||
86
modules/system/tests/classes/MarkupManagerTest.php
Normal file
86
modules/system/tests/classes/MarkupManagerTest.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Classes;
|
||||
|
||||
use System\Tests\Bootstrap\TestCase;
|
||||
use System\Classes\MarkupManager;
|
||||
|
||||
class MarkupManagerTest extends TestCase
|
||||
{
|
||||
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
include_once base_path() . '/modules/system/tests/fixtures/plugins/winter/tester/Plugin.php';
|
||||
}
|
||||
|
||||
//
|
||||
// Tests
|
||||
//
|
||||
|
||||
public function testIsWildCallable()
|
||||
{
|
||||
$manager = MarkupManager::instance();
|
||||
|
||||
/*
|
||||
* Negatives
|
||||
*/
|
||||
$callable = 'something';
|
||||
$result = self::callProtectedMethod($manager, 'isWildCallable', [$callable]);
|
||||
$this->assertFalse($result);
|
||||
|
||||
$callable = ['Form', 'open'];
|
||||
$result = self::callProtectedMethod($manager, 'isWildCallable', [$callable]);
|
||||
$this->assertFalse($result);
|
||||
|
||||
$callable = function () {
|
||||
return 'O, Hai!';
|
||||
};
|
||||
$result = self::callProtectedMethod($manager, 'isWildCallable', [$callable]);
|
||||
$this->assertFalse($result);
|
||||
|
||||
/*
|
||||
* String
|
||||
*/
|
||||
$callable = 'something_*';
|
||||
$result = self::callProtectedMethod($manager, 'isWildCallable', [$callable]);
|
||||
$this->assertTrue($result);
|
||||
|
||||
$result = self::callProtectedMethod($manager, 'isWildCallable', [$callable, 'delicious']);
|
||||
$this->assertEquals('something_delicious', $result);
|
||||
|
||||
/*
|
||||
* Array
|
||||
*/
|
||||
$callable = ['Class', 'foo_*'];
|
||||
$result = self::callProtectedMethod($manager, 'isWildCallable', [$callable]);
|
||||
$this->assertTrue($result);
|
||||
|
||||
$result = self::callProtectedMethod($manager, 'isWildCallable', [$callable, 'bar']);
|
||||
$this->assertArrayHasKey(0, $result);
|
||||
$this->assertArrayHasKey(1, $result);
|
||||
$this->assertEquals('Class', $result[0]);
|
||||
$this->assertEquals('foo_bar', $result[1]);
|
||||
|
||||
$callable = ['My*', 'method'];
|
||||
$result = self::callProtectedMethod($manager, 'isWildCallable', [$callable]);
|
||||
$this->assertTrue($result);
|
||||
|
||||
$result = self::callProtectedMethod($manager, 'isWildCallable', [$callable, 'Class']);
|
||||
$this->assertArrayHasKey(0, $result);
|
||||
$this->assertArrayHasKey(1, $result);
|
||||
$this->assertEquals('MyClass', $result[0]);
|
||||
$this->assertEquals('method', $result[1]);
|
||||
|
||||
$callable = ['My*', 'my*'];
|
||||
$result = self::callProtectedMethod($manager, 'isWildCallable', [$callable]);
|
||||
$this->assertTrue($result);
|
||||
|
||||
$result = self::callProtectedMethod($manager, 'isWildCallable', [$callable, 'Food']);
|
||||
$this->assertArrayHasKey(0, $result);
|
||||
$this->assertArrayHasKey(1, $result);
|
||||
$this->assertEquals('MyFood', $result[0]);
|
||||
$this->assertEquals('myFood', $result[1]);
|
||||
}
|
||||
}
|
||||
172
modules/system/tests/classes/MediaLibraryTest.php
Normal file
172
modules/system/tests/classes/MediaLibraryTest.php
Normal file
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Classes;
|
||||
|
||||
use System\Tests\Bootstrap\TestCase;
|
||||
use Illuminate\Filesystem\FilesystemAdapter;
|
||||
use System\Classes\MediaLibrary;
|
||||
|
||||
class MediaLibraryTest extends TestCase
|
||||
{
|
||||
public function setUp(): void
|
||||
{
|
||||
MediaLibrary::forgetInstance();
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
$this->removeMedia();
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public function invalidPathsProvider()
|
||||
{
|
||||
return [
|
||||
['./file'],
|
||||
['../secret'],
|
||||
['.../secret'],
|
||||
['/../secret'],
|
||||
['/.../secret'],
|
||||
['/secret/..'],
|
||||
['file/../secret'],
|
||||
['file/..'],
|
||||
['......./secret'],
|
||||
['./file'],
|
||||
];
|
||||
}
|
||||
|
||||
public function validPathsProvider()
|
||||
{
|
||||
return [
|
||||
['file'],
|
||||
['folder/file'],
|
||||
['/file'],
|
||||
['/folder/file'],
|
||||
['/.file'],
|
||||
['/..file'],
|
||||
['/...file'],
|
||||
['file.ext'],
|
||||
['file..ext'],
|
||||
['file...ext'],
|
||||
['one,two.ext'],
|
||||
['one(two)[].ext'],
|
||||
['one=(two)[].ext'],
|
||||
['one_(two)[].ext'],
|
||||
/*
|
||||
Example of a unicode-based filename with a single quote
|
||||
@see: https://github.com/octobercms/october/pull/4564
|
||||
*/
|
||||
['BG中国通讯期刊(Blend\'r)创刊号.pdf'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider invalidPathsProvider
|
||||
*/
|
||||
public function testInvalidPathsOnValidatePath($path)
|
||||
{
|
||||
$this->expectException('ApplicationException');
|
||||
MediaLibrary::validatePath($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider validPathsProvider
|
||||
*/
|
||||
public function testValidPathsOnValidatePath($path)
|
||||
{
|
||||
$result = MediaLibrary::validatePath($path);
|
||||
$this->assertIsString($result);
|
||||
}
|
||||
|
||||
public function testListFolderContents()
|
||||
{
|
||||
$this->setUpStorage();
|
||||
$this->copyMedia();
|
||||
|
||||
$contents = MediaLibrary::instance()->listFolderContents();
|
||||
$this->assertNotEmpty($contents, 'Media library item is not discovered');
|
||||
$this->assertCount(3, $contents);
|
||||
|
||||
$this->assertEquals('file', $contents[2]->type, 'Media library item does not have the right type');
|
||||
$this->assertEquals('/winter.png', $contents[2]->path, 'Media library item does not have the right path');
|
||||
$this->assertNotEmpty($contents[2]->lastModified, 'Media library item last modified is empty');
|
||||
$this->assertNotEmpty($contents[2]->size, 'Media library item size is empty');
|
||||
|
||||
$this->assertEquals('file', $contents[0]->type, 'Media library item does not have the right type');
|
||||
$this->assertEquals('/text.txt', $contents[0]->path, 'Media library item does not have the right path');
|
||||
$this->assertNotEmpty($contents[0]->lastModified, 'Media library item last modified is empty');
|
||||
$this->assertNotEmpty($contents[0]->size, 'Media library item size is empty');
|
||||
}
|
||||
|
||||
public function testListAllDirectories()
|
||||
{
|
||||
$disk = $this->createConfiguredMock(FilesystemAdapter::class, [
|
||||
'allDirectories' => [
|
||||
'/media/.ignore1',
|
||||
'/media/.ignore2',
|
||||
'/media/dir',
|
||||
'/media/dir/sub',
|
||||
'/media/exclude',
|
||||
'/media/hidden',
|
||||
'/media/hidden/sub1',
|
||||
'/media/hidden/sub1/deep1',
|
||||
'/media/hidden/sub2',
|
||||
'/media/hidden but not really',
|
||||
'/media/name'
|
||||
]
|
||||
]);
|
||||
|
||||
$this->app['config']->set('cms.storage.media.folder', 'media');
|
||||
$this->app['config']->set('cms.storage.media.ignore', ['hidden']);
|
||||
$this->app['config']->set('cms.storage.media.ignorePatterns', ['^\..*']);
|
||||
$instance = MediaLibrary::instance();
|
||||
$this->setProtectedProperty($instance, 'storageDisk', $disk);
|
||||
|
||||
$this->assertEquals(['/', '/dir', '/dir/sub', '/hidden but not really', '/name'], $instance->listAllDirectories(['/exclude']));
|
||||
}
|
||||
|
||||
protected function setUpStorage()
|
||||
{
|
||||
$this->app->useStoragePath(base_path('storage/temp'));
|
||||
|
||||
config(['filesystems.disks.test_local' => [
|
||||
'driver' => 'local',
|
||||
'root' => storage_path('app'),
|
||||
]]);
|
||||
|
||||
config(['cms.storage.media' => [
|
||||
'disk' => 'test_local',
|
||||
'folder' => 'media',
|
||||
'path' => '/storage/app/media',
|
||||
]]);
|
||||
}
|
||||
|
||||
protected function copyMedia()
|
||||
{
|
||||
$mediaPath = storage_path('app/media');
|
||||
|
||||
if (!is_dir($mediaPath)) {
|
||||
mkdir($mediaPath, 0777, true);
|
||||
}
|
||||
|
||||
foreach (glob(base_path('modules/system/tests/fixtures/media/*')) as $file) {
|
||||
$path = pathinfo($file);
|
||||
copy($file, $mediaPath . DIRECTORY_SEPARATOR . $path['basename']);
|
||||
}
|
||||
}
|
||||
|
||||
protected function removeMedia()
|
||||
{
|
||||
if ($this->app->storagePath() !== base_path('storage/temp')) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (glob(storage_path('app/media/*')) as $file) {
|
||||
unlink($file);
|
||||
}
|
||||
|
||||
rmdir(storage_path('app/media'));
|
||||
rmdir(storage_path('app'));
|
||||
}
|
||||
}
|
||||
67
modules/system/tests/classes/PluginBaseTest.php
Normal file
67
modules/system/tests/classes/PluginBaseTest.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Classes;
|
||||
|
||||
use System\Tests\Bootstrap\PluginManagerTestCase;
|
||||
|
||||
class PluginBaseTest extends PluginManagerTestCase
|
||||
{
|
||||
//
|
||||
// Tests
|
||||
//
|
||||
|
||||
public function testGetPluginVersions()
|
||||
{
|
||||
$expectedVersions = [
|
||||
'1.0.1' => [
|
||||
'Added some upgrade file and some "seeding"',
|
||||
'some_seeding_file.php' //does not exist
|
||||
],
|
||||
'1.0.2' => [
|
||||
'Added some stuff',
|
||||
],
|
||||
'1.0.3' => [
|
||||
'Bug fix update that uses no scripts'
|
||||
],
|
||||
'1.0.4' => [
|
||||
'Another fix'
|
||||
],
|
||||
'1.0.5' => [
|
||||
'Create blog settings table',
|
||||
'Another update message',
|
||||
'Yet one more update message',
|
||||
],
|
||||
'1.1.0' => [
|
||||
'!!! Drop support for blog settings',
|
||||
],
|
||||
'1.2.0' => [
|
||||
'!!! Security update - see: https://wintercms.com',
|
||||
],
|
||||
'1.3.0' => [
|
||||
'!!! We\'ve refactored major parts of this plugin. Please see the website for more information.',
|
||||
],
|
||||
'1.3.1' => [
|
||||
'Minor bug fix Please see changelog',
|
||||
],
|
||||
'1.3.2' => [
|
||||
'Added support for Translate plugin. Added some new languages.',
|
||||
],
|
||||
'1.4.1' => [
|
||||
'!!! Major update here.',
|
||||
],
|
||||
'1.5.0' => [
|
||||
'!!! Another major update to fix several issues',
|
||||
],
|
||||
'1.5.1' => [
|
||||
'Improved signature with the Test::method()',
|
||||
'Translation updates.',
|
||||
],
|
||||
];
|
||||
|
||||
$plugin = $this->manager->findByIdentifier('Winter.Tester');
|
||||
$versions = $plugin->getPluginVersions(false);
|
||||
|
||||
$this->assertNotNull($versions);
|
||||
$this->assertEquals($expectedVersions, $versions);
|
||||
}
|
||||
}
|
||||
498
modules/system/tests/classes/PluginManagerTest.php
Normal file
498
modules/system/tests/classes/PluginManagerTest.php
Normal file
@@ -0,0 +1,498 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Classes;
|
||||
|
||||
use System\Tests\Bootstrap\PluginManagerTestCase;
|
||||
use System\Classes\PluginManager;
|
||||
use System\Classes\PluginBase;
|
||||
|
||||
class PluginManagerTest extends PluginManagerTestCase
|
||||
{
|
||||
const INSTALLED_PLUGIN_COUNT = 17;
|
||||
const ENABLED_PLUGIN_COUNT = 14;
|
||||
const PLUGIN_NAMESPACE_COUNT = 18;
|
||||
const PLUGIN_VENDOR_COUNT = 5;
|
||||
|
||||
//
|
||||
// Tests
|
||||
//
|
||||
|
||||
public function testLoadPlugins()
|
||||
{
|
||||
$result = $this->manager->loadPlugins();
|
||||
|
||||
$this->assertCount(static::INSTALLED_PLUGIN_COUNT, $result);
|
||||
$this->assertArrayHasKey('Winter.NoUpdates', $result);
|
||||
$this->assertArrayHasKey('Winter.Sample', $result);
|
||||
$this->assertArrayHasKey('Winter.Tester', $result);
|
||||
$this->assertArrayHasKey('Database.Tester', $result);
|
||||
$this->assertArrayHasKey('TestVendor.Test', $result);
|
||||
$this->assertArrayHasKey('DependencyTest.Found', $result);
|
||||
$this->assertArrayHasKey('DependencyTest.NotFound', $result);
|
||||
$this->assertArrayHasKey('DependencyTest.WrongCase', $result);
|
||||
$this->assertArrayHasKey('DependencyTest.Dependency', $result);
|
||||
|
||||
$this->assertArrayNotHasKey('TestVendor.Goto', $result);
|
||||
|
||||
$this->assertInstanceOf('Winter\NoUpdates\Plugin', $result['Winter.NoUpdates']);
|
||||
$this->assertInstanceOf('Winter\Sample\Plugin', $result['Winter.Sample']);
|
||||
$this->assertInstanceOf('Winter\Tester\Plugin', $result['Winter.Tester']);
|
||||
$this->assertInstanceOf('Database\Tester\Plugin', $result['Database.Tester']);
|
||||
$this->assertInstanceOf('TestVendor\Test\Plugin', $result['TestVendor.Test']);
|
||||
$this->assertInstanceOf('DependencyTest\Found\Plugin', $result['DependencyTest.Found']);
|
||||
$this->assertInstanceOf('DependencyTest\NotFound\Plugin', $result['DependencyTest.NotFound']);
|
||||
$this->assertInstanceOf('DependencyTest\WrongCase\Plugin', $result['DependencyTest.WrongCase']);
|
||||
$this->assertInstanceOf('DependencyTest\Dependency\Plugin', $result['DependencyTest.Dependency']);
|
||||
}
|
||||
|
||||
public function testUnloadablePlugin()
|
||||
{
|
||||
$pluginNamespaces = $this->manager->getPluginNamespaces();
|
||||
$result = $this->manager->loadPlugin('\\testvendor\\goto', $pluginNamespaces['\\testvendor\\goto']);
|
||||
$this->assertNull($result);
|
||||
}
|
||||
|
||||
public function testGetPluginPath()
|
||||
{
|
||||
$result = $this->manager->getPluginPath('Winter\Tester');
|
||||
$basePath = str_replace('\\', '/', base_path());
|
||||
$this->assertEquals($basePath . '/modules/system/tests/fixtures/plugins/winter/tester', $result);
|
||||
}
|
||||
|
||||
public function testGetPlugins()
|
||||
{
|
||||
$result = $this->manager->getPlugins();
|
||||
|
||||
$this->assertCount(static::ENABLED_PLUGIN_COUNT, $result);
|
||||
$this->assertArrayHasKey('Winter.NoUpdates', $result);
|
||||
$this->assertArrayHasKey('Winter.Sample', $result);
|
||||
$this->assertArrayHasKey('Winter.Tester', $result);
|
||||
$this->assertArrayHasKey('Database.Tester', $result);
|
||||
$this->assertArrayHasKey('TestVendor.Test', $result);
|
||||
$this->assertArrayHasKey('DependencyTest.Found', $result);
|
||||
$this->assertArrayHasKey('DependencyTest.WrongCase', $result);
|
||||
$this->assertArrayHasKey('DependencyTest.Dependency', $result);
|
||||
|
||||
$this->assertArrayNotHasKey('DependencyTest.NotFound', $result);
|
||||
$this->assertArrayNotHasKey('TestVendor.Goto', $result);
|
||||
|
||||
$this->assertInstanceOf('Winter\NoUpdates\Plugin', $result['Winter.NoUpdates']);
|
||||
$this->assertInstanceOf('Winter\Sample\Plugin', $result['Winter.Sample']);
|
||||
$this->assertInstanceOf('Winter\Tester\Plugin', $result['Winter.Tester']);
|
||||
$this->assertInstanceOf('Database\Tester\Plugin', $result['Database.Tester']);
|
||||
$this->assertInstanceOf('TestVendor\Test\Plugin', $result['TestVendor.Test']);
|
||||
$this->assertInstanceOf('DependencyTest\Found\Plugin', $result['DependencyTest.Found']);
|
||||
$this->assertInstanceOf('DependencyTest\WrongCase\Plugin', $result['DependencyTest.WrongCase']);
|
||||
$this->assertInstanceOf('DependencyTest\Dependency\Plugin', $result['DependencyTest.Dependency']);
|
||||
}
|
||||
|
||||
public function testFindByNamespace()
|
||||
{
|
||||
$result = $this->manager->findByNamespace('Winter\Tester');
|
||||
$this->assertInstanceOf('Winter\Tester\Plugin', $result);
|
||||
}
|
||||
|
||||
public function testHasPlugin()
|
||||
{
|
||||
$result = $this->manager->hasPlugin('Winter\Tester');
|
||||
$this->assertTrue($result);
|
||||
|
||||
$result = $this->manager->hasPlugin('DependencyTest.Found');
|
||||
$this->assertTrue($result);
|
||||
|
||||
$result = $this->manager->hasPlugin('DependencyTest\WrongCase');
|
||||
$this->assertTrue($result);
|
||||
|
||||
$result = $this->manager->hasPlugin('DependencyTest\NotFound');
|
||||
$this->assertTrue($result);
|
||||
|
||||
$result = $this->manager->hasPlugin('Winter\XXXXX');
|
||||
$this->assertFalse($result);
|
||||
|
||||
/**
|
||||
* Test case for https://github.com/octobercms/october/pull/4337
|
||||
*/
|
||||
$result = $this->manager->hasPlugin('dependencyTest\Wrongcase');
|
||||
$this->assertTrue($result);
|
||||
|
||||
$result = $this->manager->hasPlugin('dependencyTest.Wrongcase');
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
public function testGetPluginNamespaces()
|
||||
{
|
||||
$result = $this->manager->getPluginNamespaces();
|
||||
|
||||
$this->assertCount(static::PLUGIN_NAMESPACE_COUNT, $result);
|
||||
$this->assertArrayHasKey('\winter\noupdates', $result);
|
||||
$this->assertArrayHasKey('\winter\sample', $result);
|
||||
$this->assertArrayHasKey('\winter\tester', $result);
|
||||
$this->assertArrayHasKey('\database\tester', $result);
|
||||
$this->assertArrayHasKey('\testvendor\test', $result);
|
||||
$this->assertArrayHasKey('\testvendor\goto', $result);
|
||||
$this->assertArrayHasKey('\dependencytest\found', $result);
|
||||
$this->assertArrayHasKey('\dependencytest\notfound', $result);
|
||||
$this->assertArrayHasKey('\dependencytest\wrongcase', $result);
|
||||
$this->assertArrayHasKey('\dependencytest\dependency', $result);
|
||||
}
|
||||
|
||||
public function testGetVendorAndPluginNames()
|
||||
{
|
||||
$vendors = $this->manager->getVendorAndPluginNames();
|
||||
|
||||
$this->assertCount(static::PLUGIN_VENDOR_COUNT, $vendors);
|
||||
$this->assertArrayHasKey('winter', $vendors);
|
||||
$this->assertArrayHasKey('noupdates', $vendors['winter']);
|
||||
$this->assertArrayHasKey('sample', $vendors['winter']);
|
||||
$this->assertArrayHasKey('tester', $vendors['winter']);
|
||||
|
||||
$this->assertArrayHasKey('database', $vendors);
|
||||
$this->assertArrayHasKey('tester', $vendors['database']);
|
||||
|
||||
$this->assertArrayHasKey('testvendor', $vendors);
|
||||
$this->assertArrayHasKey('test', $vendors['testvendor']);
|
||||
$this->assertArrayHasKey('goto', $vendors['testvendor']);
|
||||
|
||||
$this->assertArrayHasKey('dependencytest', $vendors);
|
||||
$this->assertArrayHasKey('found', $vendors['dependencytest']);
|
||||
$this->assertArrayHasKey('notfound', $vendors['dependencytest']);
|
||||
$this->assertArrayHasKey('wrongcase', $vendors['dependencytest']);
|
||||
$this->assertArrayHasKey('dependency', $vendors['dependencytest']);
|
||||
}
|
||||
|
||||
public function testPluginDetails()
|
||||
{
|
||||
$testPlugin = $this->manager->findByNamespace('Winter\XXXXX');
|
||||
$this->assertNull($testPlugin);
|
||||
|
||||
$testPlugin = $this->manager->findByNamespace('Winter\Tester');
|
||||
$this->assertNotNull($testPlugin);
|
||||
$pluginDetails = $testPlugin->pluginDetails();
|
||||
|
||||
$this->assertEquals('Winter Test Plugin', $pluginDetails['name']);
|
||||
$this->assertEquals('Test plugin used by unit tests.', $pluginDetails['description']);
|
||||
$this->assertEquals('Alexey Bobkov, Samuel Georges', $pluginDetails['author']);
|
||||
}
|
||||
|
||||
public function testUnregisterall()
|
||||
{
|
||||
$result = $this->manager->getPlugins();
|
||||
$this->assertCount(static::ENABLED_PLUGIN_COUNT, $result);
|
||||
|
||||
$this->manager->unregisterAll();
|
||||
$this->assertEmpty($this->manager->getPlugins());
|
||||
}
|
||||
|
||||
public function testGetDependencies()
|
||||
{
|
||||
$result = $this->manager->getDependencies('DependencyTest.Found');
|
||||
$this->assertCount(1, $result);
|
||||
$this->assertContains('DependencyTest.Dependency', $result);
|
||||
|
||||
$result = $this->manager->getDependencies('DependencyTest.WrongCase');
|
||||
$this->assertCount(1, $result);
|
||||
$this->assertContains('Dependencytest.dependency', $result);
|
||||
|
||||
$result = $this->manager->getDependencies('DependencyTest.NotFound');
|
||||
$this->assertCount(1, $result);
|
||||
$this->assertContains('DependencyTest.Missing', $result);
|
||||
}
|
||||
|
||||
public function testIsDisabled()
|
||||
{
|
||||
$result = $this->manager->isDisabled('DependencyTest.Found');
|
||||
$this->assertFalse($result);
|
||||
|
||||
$result = $this->manager->isDisabled('DependencyTest.WrongCase');
|
||||
$this->assertFalse($result);
|
||||
|
||||
$result = $this->manager->isDisabled('DependencyTest.NotFound');
|
||||
$this->assertTrue($result);
|
||||
|
||||
/**
|
||||
* Test case for https://github.com/octobercms/october/pull/4838
|
||||
*/
|
||||
$result = $this->manager->isDisabled('dependencyTest\Wrongcase');
|
||||
$this->assertFalse($result);
|
||||
|
||||
$result = $this->manager->isDisabled('dependencyTest.Wrongcase');
|
||||
$this->assertFalse($result);
|
||||
|
||||
$result = $this->manager->isDisabled('dependencytest.notfound');
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
public function testExists()
|
||||
{
|
||||
$result = $this->manager->exists('DependencyTest.Found');
|
||||
$this->assertTrue($result);
|
||||
|
||||
$result = $this->manager->exists('DependencyTest.WrongCase');
|
||||
$this->assertTrue($result);
|
||||
|
||||
$result = $this->manager->exists('DependencyTest.NotFound');
|
||||
$this->assertFalse($result);
|
||||
|
||||
$result = $this->manager->exists('Unknown.Plugin');
|
||||
$this->assertFalse($result);
|
||||
}
|
||||
|
||||
public function testReplacement()
|
||||
{
|
||||
$this->assertFalse($this->manager->isDisabled('Winter.Replacement'));
|
||||
$this->assertTrue($this->manager->isDisabled('Winter.Original'));
|
||||
$this->assertTrue($this->manager->isDisabled('Winter.InvalidReplacement'));
|
||||
|
||||
$this->assertEquals('Winter.Replacement', $this->manager->findByIdentifier('Winter.Original')->getPluginIdentifier());
|
||||
}
|
||||
|
||||
public function testHasPluginReplacement()
|
||||
{
|
||||
// check a replaced plugin
|
||||
$this->assertTrue($this->manager->hasPlugin('Winter.Original'));
|
||||
$this->assertTrue($this->manager->isDisabled('Winter.Original'));
|
||||
// check a replacement plugin
|
||||
$this->assertTrue($this->manager->hasPlugin('Winter.Replacement'));
|
||||
$this->assertFalse($this->manager->isDisabled('Winter.Replacement'));
|
||||
// check a plugin where the replacement is invalid
|
||||
$this->assertTrue($this->manager->hasPlugin('Winter.InvalidReplacement'));
|
||||
$this->assertTrue($this->manager->isDisabled('Winter.InvalidReplacement'));
|
||||
// check a plugin replacing a plugin not found on disk
|
||||
$this->assertTrue($this->manager->hasPlugin('Winter.ReplaceNotInstalled'));
|
||||
$this->assertFalse($this->manager->isDisabled('Winter.ReplaceNotInstalled'));
|
||||
// ensure searching for the alias of a replacement (plugin not installed)
|
||||
$this->assertTrue($this->manager->hasPlugin('Winter.NotInstalled'));
|
||||
|
||||
$this->assertInstanceOf(\Winter\Replacement\Plugin::class, $this->manager->findByIdentifier('Winter.Original'));
|
||||
$this->assertInstanceOf(\Winter\Replacement\Plugin::class, $this->manager->findByIdentifier('Winter.Replacement'));
|
||||
|
||||
// check getting a plugin via it's not installed original plugin identifier
|
||||
$this->assertInstanceOf(\Winter\ReplaceNotInstalled\Plugin::class, $this->manager->findByIdentifier('Winter.NotInstalled'));
|
||||
$this->assertNull($this->manager->findByIdentifier('Winter.NotInstalled', true));
|
||||
|
||||
// force getting the original plugin
|
||||
$this->assertInstanceOf(\Winter\Original\Plugin::class, $this->manager->findByIdentifier('Winter.Original', true));
|
||||
}
|
||||
|
||||
public function testHasPluginReplacementMixedCase()
|
||||
{
|
||||
// test checking casing of installed plugin (resolved via getNormalizedIdentifier())
|
||||
$this->assertTrue($this->manager->hasPlugin('Winter.ReplaceNotInstalled'));
|
||||
$this->assertTrue($this->manager->hasPlugin('Winter.replaceNotInstalled'));
|
||||
$this->assertTrue($this->manager->hasPlugin('Winter.replacenotInstalled'));
|
||||
$this->assertTrue($this->manager->hasPlugin('winter.replacenotInstalled'));
|
||||
$this->assertTrue($this->manager->hasPlugin('winter.replacenotinstalled'));
|
||||
|
||||
// test checking casing of installed replaced plugin (resolved via getNormalizedIdentifier() & replacementMap)
|
||||
$this->assertTrue($this->manager->hasPlugin('Winter.Original'));
|
||||
$this->assertTrue($this->manager->hasPlugin('Winter.original'));
|
||||
$this->assertTrue($this->manager->hasPlugin('winter.original'));
|
||||
|
||||
// test checking casing of uninstalled plugin (resolved via strtolower() on replacement keys)
|
||||
$this->assertTrue($this->manager->hasPlugin('Winter.NotInstalled'));
|
||||
$this->assertTrue($this->manager->hasPlugin('Winter.notInstalled'));
|
||||
$this->assertTrue($this->manager->hasPlugin('winter.notInstalled'));
|
||||
$this->assertTrue($this->manager->hasPlugin('Winter.notinstalled'));
|
||||
}
|
||||
|
||||
public function testExistsReplacementMixedCase()
|
||||
{
|
||||
// test checking casing of installed plugin (resolved via getNormalizedIdentifier())
|
||||
$this->assertTrue($this->manager->exists('Winter.ReplaceNotInstalled'));
|
||||
$this->assertTrue($this->manager->exists('Winter.replaceNotInstalled'));
|
||||
$this->assertTrue($this->manager->exists('Winter.replacenotInstalled'));
|
||||
$this->assertTrue($this->manager->exists('winter.replacenotInstalled'));
|
||||
$this->assertTrue($this->manager->exists('winter.replacenotinstalled'));
|
||||
|
||||
// test checking casing of installed replaced plugin (resolved via getNormalizedIdentifier() & replacementMap)
|
||||
$this->assertFalse($this->manager->exists('Winter.Original'));
|
||||
$this->assertFalse($this->manager->exists('Winter.original'));
|
||||
$this->assertFalse($this->manager->exists('winter.original'));
|
||||
|
||||
// test checking casing of uninstalled plugin (resolved via strtolower() on replacement keys)
|
||||
$this->assertTrue($this->manager->exists('Winter.NotInstalled'));
|
||||
$this->assertTrue($this->manager->exists('Winter.notInstalled'));
|
||||
$this->assertTrue($this->manager->exists('winter.notInstalled'));
|
||||
$this->assertTrue($this->manager->exists('Winter.notinstalled'));
|
||||
}
|
||||
|
||||
public function testFindByIdentifierReplacementMixedCase()
|
||||
{
|
||||
// test resolving plugin with mixed casing
|
||||
$this->assertInstanceOf(\Winter\ReplaceNotInstalled\Plugin::class, $this->manager->findByIdentifier('Winter.ReplaceNotInstalled'));
|
||||
$this->assertInstanceOf(\Winter\ReplaceNotInstalled\Plugin::class, $this->manager->findByIdentifier('Winter.replaceNotInstalled'));
|
||||
$this->assertInstanceOf(\Winter\ReplaceNotInstalled\Plugin::class, $this->manager->findByIdentifier('Winter.replacenotInstalled'));
|
||||
$this->assertInstanceOf(\Winter\ReplaceNotInstalled\Plugin::class, $this->manager->findByIdentifier('winter.replacenotInstalled'));
|
||||
$this->assertInstanceOf(\Winter\ReplaceNotInstalled\Plugin::class, $this->manager->findByIdentifier('winter.replacenotinstalled'));
|
||||
|
||||
// test resolving replacement plugin with mixed casing
|
||||
$this->assertInstanceOf(\Winter\Replacement\Plugin::class, $this->manager->findByIdentifier('Winter.Original'));
|
||||
$this->assertInstanceOf(\Winter\Replacement\Plugin::class, $this->manager->findByIdentifier('Winter.original'));
|
||||
$this->assertInstanceOf(\Winter\Replacement\Plugin::class, $this->manager->findByIdentifier('winter.original'));
|
||||
|
||||
// test resolving original plugin with mixed casing when ignoring replacements
|
||||
$this->assertInstanceOf(\Winter\Original\Plugin::class, $this->manager->findByIdentifier('Winter.Original', true));
|
||||
$this->assertInstanceOf(\Winter\Original\Plugin::class, $this->manager->findByIdentifier('Winter.original', true));
|
||||
$this->assertInstanceOf(\Winter\Original\Plugin::class, $this->manager->findByIdentifier('winter.original', true));
|
||||
|
||||
// test resolving replacement plugin of uninstalled plugin with mixed casing
|
||||
$this->assertInstanceOf(\Winter\ReplaceNotInstalled\Plugin::class, $this->manager->findByIdentifier('Winter.NotInstalled'));
|
||||
$this->assertInstanceOf(\Winter\ReplaceNotInstalled\Plugin::class, $this->manager->findByIdentifier('Winter.notInstalled'));
|
||||
$this->assertInstanceOf(\Winter\ReplaceNotInstalled\Plugin::class, $this->manager->findByIdentifier('winter.notInstalled'));
|
||||
$this->assertInstanceOf(\Winter\ReplaceNotInstalled\Plugin::class, $this->manager->findByIdentifier('Winter.notinstalled'));
|
||||
}
|
||||
|
||||
public function testGetReplacements()
|
||||
{
|
||||
$replacementPluginReplaces = $this->manager->findByIdentifier('Winter.Replacement')->getReplaces();
|
||||
|
||||
$this->assertIsArray($replacementPluginReplaces);
|
||||
$this->assertCount(1, $replacementPluginReplaces);
|
||||
$this->assertEquals('Winter.Original', $replacementPluginReplaces[0]);
|
||||
|
||||
$invalidPluginReplaces = $this->manager->findByIdentifier('Winter.InvalidReplacement')->getReplaces();
|
||||
|
||||
$this->assertIsArray($invalidPluginReplaces);
|
||||
$this->assertCount(1, $invalidPluginReplaces);
|
||||
$this->assertEquals('Winter.Tester', $invalidPluginReplaces[0]);
|
||||
}
|
||||
|
||||
public function testReplaceVersion()
|
||||
{
|
||||
$invalidReplacementPlugin = $this->manager->findByIdentifier('Winter.InvalidReplacement');
|
||||
|
||||
$this->assertTrue($invalidReplacementPlugin->canReplacePlugin('Winter.Tester', '9'));
|
||||
$this->assertTrue($invalidReplacementPlugin->canReplacePlugin('Winter.Tester', '9.0'));
|
||||
$this->assertTrue($invalidReplacementPlugin->canReplacePlugin('Winter.Tester', '11.0.0'));
|
||||
$this->assertFalse($invalidReplacementPlugin->canReplacePlugin('Winter.Tester', '8.0'));
|
||||
|
||||
$replacementPlugin = $this->manager->findByIdentifier('Winter.Replacement');
|
||||
|
||||
$this->assertTrue($replacementPlugin->canReplacePlugin('Winter.Original', '1.0.2'));
|
||||
$this->assertTrue($replacementPlugin->canReplacePlugin('Winter.Original', '1.0'));
|
||||
$this->assertFalse($replacementPlugin->canReplacePlugin('Winter.Original', '2.0.1'));
|
||||
}
|
||||
|
||||
public function testActiveReplacementMap()
|
||||
{
|
||||
$map = $this->manager->getActiveReplacementMap();
|
||||
$this->assertArrayHasKey('Winter.Original', $map);
|
||||
$this->assertEquals('Winter.Replacement', $map['Winter.Original']);
|
||||
|
||||
$this->assertEquals('Winter.Replacement', $this->manager->getActiveReplacementMap('Winter.Original'));
|
||||
$this->assertNull($this->manager->getActiveReplacementMap('Winter.InvalidReplacement'));
|
||||
}
|
||||
|
||||
public function testFlagDisableStatus()
|
||||
{
|
||||
$plugin = $this->manager->findByIdentifier('DependencyTest.Dependency');
|
||||
$flags = $this->manager->getPluginFlags($plugin);
|
||||
$this->assertEmpty($flags);
|
||||
|
||||
$plugin = $this->manager->findByIdentifier('DependencyTest.NotFound');
|
||||
$flags = $this->manager->getPluginFlags($plugin);
|
||||
$this->assertCount(1, $flags);
|
||||
$this->assertArrayHasKey(PluginManager::DISABLED_MISSING_DEPENDENCIES, $flags);
|
||||
|
||||
$plugin = $this->manager->findByIdentifier('Winter.InvalidReplacement');
|
||||
$flags = $this->manager->getPluginFlags($plugin);
|
||||
$this->assertCount(1, $flags);
|
||||
$this->assertArrayHasKey(PluginManager::DISABLED_REPLACEMENT_FAILED, $flags);
|
||||
|
||||
$plugin = $this->manager->findByIdentifier('Winter.Original', true);
|
||||
$flags = $this->manager->getPluginFlags($plugin);
|
||||
$this->assertCount(1, $flags);
|
||||
$this->assertArrayHasKey(PluginManager::DISABLED_REPLACED, $flags);
|
||||
}
|
||||
|
||||
public function testFlagDisabling()
|
||||
{
|
||||
$plugin = $this->manager->findByIdentifier('Winter.Tester', true);
|
||||
|
||||
$flags = $this->manager->getPluginFlags($plugin);
|
||||
$this->assertEmpty($flags);
|
||||
|
||||
$this->manager->disablePlugin($plugin);
|
||||
|
||||
$flags = $this->manager->getPluginFlags($plugin);
|
||||
$this->assertCount(1, $flags);
|
||||
$this->assertArrayHasKey(PluginManager::DISABLED_BY_USER, $flags);
|
||||
|
||||
$this->manager->enablePlugin($plugin);
|
||||
|
||||
$flags = $this->manager->getPluginFlags($plugin);
|
||||
$this->assertEmpty($flags);
|
||||
|
||||
$this->manager->disablePlugin($plugin, PluginManager::DISABLED_BY_CONFIG);
|
||||
|
||||
$flags = $this->manager->getPluginFlags($plugin);
|
||||
$this->assertCount(1, $flags);
|
||||
$this->assertArrayHasKey(PluginManager::DISABLED_BY_CONFIG, $flags);
|
||||
|
||||
$this->manager->enablePlugin($plugin, PluginManager::DISABLED_BY_CONFIG);
|
||||
|
||||
$flags = $this->manager->getPluginFlags($plugin);
|
||||
$this->assertEmpty($flags);
|
||||
}
|
||||
|
||||
public function testPluginNormalization()
|
||||
{
|
||||
// test lower to upper
|
||||
$this->assertEquals('Database.Tester', $this->manager->normalizeIdentifier('database.tester'));
|
||||
$this->assertEquals('Database.Tester', $this->manager->getNormalizedIdentifier('database.tester'));
|
||||
|
||||
// test exact match
|
||||
$this->assertEquals('DependencyTest.Found', $this->manager->normalizeIdentifier('DependencyTest.Found'));
|
||||
$this->assertEquals('DependencyTest.Found', $this->manager->getNormalizedIdentifier('DependencyTest.Found'));
|
||||
|
||||
// test mixed case
|
||||
$this->assertEquals('DependencyTest.Found', $this->manager->normalizeIdentifier('Dependencytest.Found'));
|
||||
$this->assertEquals('DependencyTest.Found', $this->manager->getNormalizedIdentifier('Dependencytest.Found'));
|
||||
|
||||
// test typeo
|
||||
$this->assertEquals('dpendencytest.Found', $this->manager->normalizeIdentifier('dpendencytest.Found'));
|
||||
$this->assertEquals('dpendencytest.Found', $this->manager->getNormalizedIdentifier('dpendencytest.Found'));
|
||||
$this->assertEquals('Winter.NoUpdate', $this->manager->normalizeIdentifier('Winter.NoUpdate'));
|
||||
$this->assertEquals('Winter.NoUpdate', $this->manager->getNormalizedIdentifier('Winter.NoUpdate'));
|
||||
|
||||
// test multiple mixed case installed plugin
|
||||
$this->assertEquals('Winter.NoUpdates', $this->manager->normalizeIdentifier('Winter.NoUpdates'));
|
||||
$this->assertEquals('Winter.NoUpdates', $this->manager->normalizeIdentifier('winter.noUpdates'));
|
||||
$this->assertEquals('Winter.NoUpdates', $this->manager->normalizeIdentifier('winter.noupdates'));
|
||||
$this->assertEquals('Winter.NoUpdates', $this->manager->getNormalizedIdentifier('Winter.NoUpdates'));
|
||||
$this->assertEquals('Winter.NoUpdates', $this->manager->getNormalizedIdentifier('winter.noUpdates'));
|
||||
$this->assertEquals('Winter.NoUpdates', $this->manager->getNormalizedIdentifier('winter.noupdates'));
|
||||
|
||||
// test multiple mixed case not installed plugin
|
||||
$this->assertEquals('Winter.MissingPlugin', $this->manager->normalizeIdentifier('Winter.MissingPlugin'));
|
||||
$this->assertEquals('Winter.Missingplugin', $this->manager->normalizeIdentifier('Winter.Missingplugin'));
|
||||
$this->assertEquals('Winter.missingplugin', $this->manager->normalizeIdentifier('Winter.missingplugin'));
|
||||
$this->assertEquals('winter.missingplugin', $this->manager->normalizeIdentifier('winter.missingplugin'));
|
||||
$this->assertEquals('Winter.MissingPlugin', $this->manager->getNormalizedIdentifier('Winter.MissingPlugin'));
|
||||
$this->assertEquals('Winter.Missingplugin', $this->manager->getNormalizedIdentifier('Winter.Missingplugin'));
|
||||
$this->assertEquals('Winter.missingplugin', $this->manager->getNormalizedIdentifier('Winter.missingplugin'));
|
||||
$this->assertEquals('winter.missingplugin', $this->manager->getNormalizedIdentifier('winter.missingplugin'));
|
||||
|
||||
// test passing plugin object
|
||||
$plugin = $this->manager->findByIdentifier('Winter.NoUpdates');
|
||||
$this->assertInstanceOf(PluginBase::class, $plugin);
|
||||
|
||||
$this->assertEquals('Winter.NoUpdates', $this->manager->getNormalizedIdentifier($plugin));
|
||||
}
|
||||
|
||||
public function testSortPluginDependencies()
|
||||
{
|
||||
$result = $this->manager->getPlugins();
|
||||
|
||||
$this->assertGreaterThan(
|
||||
array_search('DependencyTest.Dependency', array_keys($result)),
|
||||
array_search('DependencyTest.Found', array_keys($result))
|
||||
);
|
||||
|
||||
// check to make sure dependency comes first and didn't stay in alphanumeric order.
|
||||
$this->assertGreaterThan(
|
||||
array_search('DependencyTest.Dependency', array_keys($result)),
|
||||
array_search('DependencyTest.Acme', array_keys($result))
|
||||
);
|
||||
}
|
||||
}
|
||||
341
modules/system/tests/classes/SourceManifestTest.php
Normal file
341
modules/system/tests/classes/SourceManifestTest.php
Normal file
@@ -0,0 +1,341 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Classes;
|
||||
|
||||
use System\Tests\Bootstrap\TestCase;
|
||||
use Winter\Storm\Argon\Argon;
|
||||
use System\Classes\SourceManifest;
|
||||
use System\Classes\FileManifest;
|
||||
|
||||
class SourceManifestTest extends TestCase
|
||||
{
|
||||
/** @var SourceManifest instance */
|
||||
protected $sourceManifest;
|
||||
|
||||
/** @var array Emulated builds from the manifest fixture */
|
||||
protected $builds;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->builds = [
|
||||
'1.0.0' => new FileManifest(
|
||||
base_path('modules/system/tests/fixtures/manifest/1_0_0'),
|
||||
['test', 'test2']
|
||||
),
|
||||
'1.0.1' => new FileManifest(
|
||||
base_path('modules/system/tests/fixtures/manifest/1_0_1'),
|
||||
['test', 'test2']
|
||||
),
|
||||
'1.0.2' => new FileManifest(
|
||||
base_path('modules/system/tests/fixtures/manifest/1_0_2'),
|
||||
['test', 'test2']
|
||||
),
|
||||
'1.1.0' => new FileManifest(
|
||||
base_path('modules/system/tests/fixtures/manifest/1_1_0'),
|
||||
['test', 'test2', 'test3']
|
||||
),
|
||||
'1.1.1' => new FileManifest(
|
||||
base_path('modules/system/tests/fixtures/manifest/1_1_1'),
|
||||
['test', 'test2', 'test3']
|
||||
),
|
||||
'1.0.3' => new FileManifest(
|
||||
base_path('modules/system/tests/fixtures/manifest/1_0_3'),
|
||||
['test', 'test2']
|
||||
),
|
||||
];
|
||||
|
||||
$this->sourceManifest = new SourceManifest($this->manifestPath(), $this->forksPath(), false);
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
Argon::setTestNow();
|
||||
$this->deleteManifest();
|
||||
}
|
||||
|
||||
public function testCreateManifest()
|
||||
{
|
||||
// Freeze date for test
|
||||
$testDate = Argon::create(2020, 12, 16, 12, 01, 0, 'UTC');
|
||||
Argon::setTestNow($testDate);
|
||||
|
||||
$this->createManifest(true);
|
||||
|
||||
$this->assertEquals(
|
||||
'{' . "\n" .
|
||||
' "_description": "This is the source manifest of changes to Winter CMS for each version. This is used to determine which version of Winter CMS is in use, via the \"winter:version\" Artisan command.",' . "\n" .
|
||||
' "_created": "2020-12-16T12:01:00+00:00",' . "\n" .
|
||||
' "manifest": [' . "\n" .
|
||||
' {' . "\n" .
|
||||
' "build": "1.0.0",' . "\n" .
|
||||
' "parent": null,' . "\n" .
|
||||
' "modules": {' . "\n" .
|
||||
' "test": "e1d6c6e4c482688e231ee37d89668268426512013695de47bfcb424f9a645c7b",' . "\n" .
|
||||
' "test2": "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"' . "\n" .
|
||||
' },' . "\n" .
|
||||
' "files": {' . "\n" .
|
||||
' "added": {' . "\n" .
|
||||
' "\/modules\/test\/file1.php": "6f9b0b94528a85b2a6bb67b5621e074aef1b4c9fc9ee3ea1bd69100ea14cb3db"' . "\n" .
|
||||
' }' . "\n" .
|
||||
' }' . "\n" .
|
||||
' },' . "\n" .
|
||||
' {' . "\n" .
|
||||
' "build": "1.0.1",' . "\n" .
|
||||
' "parent": "1.0.0",' . "\n" .
|
||||
' "modules": {' . "\n" .
|
||||
' "test": "c0b794ff210862a4ce16223802efe6e28969f5a4fb42480ec8c2fef2da23d181",' . "\n" .
|
||||
' "test2": "32c9f2fb6e0a22dde288a0fe1e4834798360b25e5a91d2597409d9302221381d"' . "\n" .
|
||||
' },' . "\n" .
|
||||
' "files": {' . "\n" .
|
||||
' "added": {' . "\n" .
|
||||
' "\/modules\/test\/file2.php": "96ae9f6b6377ad29226ea169f952de49fc29ae895f18a2caed76aeabdf050f1b",' . "\n" .
|
||||
' "\/modules\/test2\/file1.php": "94bd47b1ac7b2837b31883ebcd38c8101687321f497c3c4b9744f68ae846721d"' . "\n" .
|
||||
' }' . "\n" .
|
||||
' }' . "\n" .
|
||||
' },' . "\n" .
|
||||
' {' . "\n" .
|
||||
' "build": "1.0.2",' . "\n" .
|
||||
' "parent": "1.0.1",' . "\n" .
|
||||
' "modules": {' . "\n" .
|
||||
' "test": "419a3c073a4296213cdc9319cfc488383753e2e81cefa1c73db38749b82a3c51",' . "\n" .
|
||||
' "test2": "32c9f2fb6e0a22dde288a0fe1e4834798360b25e5a91d2597409d9302221381d"' . "\n" .
|
||||
' },' . "\n" .
|
||||
' "files": {' . "\n" .
|
||||
' "added": {' . "\n" .
|
||||
' "\/modules\/test\/file3.php": "7f4132b05911a6b0df4d41bf5dc3d007786b63a5a22daf3060ed222816d57b54"' . "\n" .
|
||||
' },' . "\n" .
|
||||
' "modified": {' . "\n" .
|
||||
' "\/modules\/test\/file2.php": "2c61b2f5688275574251a19a57e06a4eb9e537b3916ebf6f71768e184a4ae538"' . "\n" .
|
||||
' },' . "\n" .
|
||||
' "removed": [' . "\n" .
|
||||
' "\/modules\/test\/file1.php"' . "\n" .
|
||||
' ]' . "\n" .
|
||||
' }' . "\n" .
|
||||
' },' . "\n" .
|
||||
' {' . "\n" .
|
||||
' "build": "1.0.3",' . "\n" .
|
||||
' "parent": "1.0.2",' . "\n" .
|
||||
' "modules": {' . "\n" .
|
||||
' "test": "5316f172ac24aaa7713c97885e2e27f5c5c1e02f96fcb8e269903d737d52c7bd",' . "\n" .
|
||||
' "test2": "18fc53cb280cc7e43d47e55a66b1245992c331f368106c13024572dc9fb215f7"' . "\n" .
|
||||
' },' . "\n" .
|
||||
' "files": {' . "\n" .
|
||||
' "modified": {' . "\n" .
|
||||
' "\/modules\/test2\/file1.php": "e284e816365653b5f7ddfca9319c24716cadfa3538e0c79994f0416e964da513"' . "\n" .
|
||||
' },' . "\n" .
|
||||
' "removed": [' . "\n" .
|
||||
' "\/modules\/test\/file3.php"' . "\n" .
|
||||
' ]' . "\n" .
|
||||
' }' . "\n" .
|
||||
' },' . "\n" .
|
||||
' {' . "\n" .
|
||||
' "build": "1.1.0",' . "\n" .
|
||||
' "parent": "1.0.2",' . "\n" .
|
||||
' "modules": {' . "\n" .
|
||||
' "test": "e30811c9ad3119394edefd2f2fc0bae5fc08e2a03220ccc94e2a3f078da0df6d",' . "\n" .
|
||||
' "test2": "2066b3cffe4f03b06c3399dba4d56147e4247b8071e19fa597a2e15dec697f5e",' . "\n" .
|
||||
' "test3": "3679fa86c8d92a4474a01fc41abc24ebf34b847d7288434028a0559a10ff5d33"' . "\n" .
|
||||
' },' . "\n" .
|
||||
' "files": {' . "\n" .
|
||||
' "added": {' . "\n" .
|
||||
' "\/modules\/test\/file4.php": "18047babf2625ed8f42d779f14539449e23ccfdc92f79818f291eb1c55ff0533",' . "\n" .
|
||||
' "\/modules\/test3\/file1.php": "1b691b48b8247af3dd8046a70e5678b77e66ada13b86c3a269a6428425c3a835"' . "\n" .
|
||||
' },' . "\n" .
|
||||
' "modified": {' . "\n" .
|
||||
' "\/modules\/test\/file3.php": "65b1d6f8a1a0f2dfbe870faba9fa2ee0b6f4c291656df6cd66158e166a2680eb",' . "\n" .
|
||||
' "\/modules\/test2\/file1.php": "5197bcc06443799c71fea8cb608cee61d9edd611ea23ea603aa0420393e014ca"' . "\n" .
|
||||
' },' . "\n" .
|
||||
' "removed": [' . "\n" .
|
||||
' "\/modules\/test\/file2.php"' . "\n" .
|
||||
' ]' . "\n" .
|
||||
' }' . "\n" .
|
||||
' },' . "\n" .
|
||||
' {' . "\n" .
|
||||
' "build": "1.1.1",' . "\n" .
|
||||
' "parent": "1.1.0",' . "\n" .
|
||||
' "modules": {' . "\n" .
|
||||
' "test": "e30811c9ad3119394edefd2f2fc0bae5fc08e2a03220ccc94e2a3f078da0df6d",' . "\n" .
|
||||
' "test2": "18fc53cb280cc7e43d47e55a66b1245992c331f368106c13024572dc9fb215f7",' . "\n" .
|
||||
' "test3": "728ff099502e8d40cc6a432fdeba7185b9cb5cb530dcd8f5741ec56fcd37d189"' . "\n" .
|
||||
' },' . "\n" .
|
||||
' "files": {' . "\n" .
|
||||
' "added": {' . "\n" .
|
||||
' "\/modules\/test3\/file2.php": "0614afe438a4e74547a7036ef895008c36895a783eb8e0b458691f631138d310"' . "\n" .
|
||||
' },' . "\n" .
|
||||
' "modified": {' . "\n" .
|
||||
' "\/modules\/test2\/file1.php": "e284e816365653b5f7ddfca9319c24716cadfa3538e0c79994f0416e964da513",' . "\n" .
|
||||
' "\/modules\/test3\/file1.php": "d9aeb0853bc0f21a836f2d1cd5fc224d64ce8ea9e7e22c43b1a00f25d37c42f8"' . "\n" .
|
||||
' }' . "\n" .
|
||||
' }' . "\n" .
|
||||
' }' . "\n" .
|
||||
' ]' . "\n" .
|
||||
'}',
|
||||
file_get_contents($this->manifestPath())
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetBuilds()
|
||||
{
|
||||
$this->createManifest();
|
||||
|
||||
$buildKeys = $this->sourceManifest->getBuilds();
|
||||
|
||||
$this->assertCount(6, $buildKeys);
|
||||
$this->assertEquals(['1.0.0', '1.0.1', '1.0.2', '1.0.3', '1.1.0', '1.1.1'], $buildKeys);
|
||||
}
|
||||
|
||||
public function testGetState()
|
||||
{
|
||||
$this->createManifest();
|
||||
|
||||
$this->assertEquals([
|
||||
'/modules/test/file1.php' => '6f9b0b94528a85b2a6bb67b5621e074aef1b4c9fc9ee3ea1bd69100ea14cb3db',
|
||||
], $this->sourceManifest->getState('1.0.0'));
|
||||
|
||||
$this->assertEquals([
|
||||
'/modules/test/file1.php' => '6f9b0b94528a85b2a6bb67b5621e074aef1b4c9fc9ee3ea1bd69100ea14cb3db',
|
||||
'/modules/test/file2.php' => '96ae9f6b6377ad29226ea169f952de49fc29ae895f18a2caed76aeabdf050f1b',
|
||||
'/modules/test2/file1.php' => '94bd47b1ac7b2837b31883ebcd38c8101687321f497c3c4b9744f68ae846721d',
|
||||
], $this->sourceManifest->getState('1.0.1'));
|
||||
|
||||
$this->assertEquals([
|
||||
'/modules/test/file2.php' => '2c61b2f5688275574251a19a57e06a4eb9e537b3916ebf6f71768e184a4ae538',
|
||||
'/modules/test/file3.php' => '7f4132b05911a6b0df4d41bf5dc3d007786b63a5a22daf3060ed222816d57b54',
|
||||
'/modules/test2/file1.php' => '94bd47b1ac7b2837b31883ebcd38c8101687321f497c3c4b9744f68ae846721d',
|
||||
], $this->sourceManifest->getState('1.0.2'));
|
||||
|
||||
$this->assertEquals([
|
||||
'/modules/test/file2.php' => '2c61b2f5688275574251a19a57e06a4eb9e537b3916ebf6f71768e184a4ae538',
|
||||
'/modules/test2/file1.php' => 'e284e816365653b5f7ddfca9319c24716cadfa3538e0c79994f0416e964da513',
|
||||
], $this->sourceManifest->getState('1.0.3'));
|
||||
|
||||
$this->assertEquals([
|
||||
'/modules/test/file3.php' => '65b1d6f8a1a0f2dfbe870faba9fa2ee0b6f4c291656df6cd66158e166a2680eb',
|
||||
'/modules/test/file4.php' => '18047babf2625ed8f42d779f14539449e23ccfdc92f79818f291eb1c55ff0533',
|
||||
'/modules/test2/file1.php' => '5197bcc06443799c71fea8cb608cee61d9edd611ea23ea603aa0420393e014ca',
|
||||
'/modules/test3/file1.php' => '1b691b48b8247af3dd8046a70e5678b77e66ada13b86c3a269a6428425c3a835',
|
||||
], $this->sourceManifest->getState('1.1.0'));
|
||||
|
||||
$this->assertEquals([
|
||||
'/modules/test/file3.php' => '65b1d6f8a1a0f2dfbe870faba9fa2ee0b6f4c291656df6cd66158e166a2680eb',
|
||||
'/modules/test/file4.php' => '18047babf2625ed8f42d779f14539449e23ccfdc92f79818f291eb1c55ff0533',
|
||||
'/modules/test2/file1.php' => 'e284e816365653b5f7ddfca9319c24716cadfa3538e0c79994f0416e964da513',
|
||||
'/modules/test3/file1.php' => 'd9aeb0853bc0f21a836f2d1cd5fc224d64ce8ea9e7e22c43b1a00f25d37c42f8',
|
||||
'/modules/test3/file2.php' => '0614afe438a4e74547a7036ef895008c36895a783eb8e0b458691f631138d310',
|
||||
], $this->sourceManifest->getState('1.1.1'));
|
||||
}
|
||||
|
||||
public function testCompare()
|
||||
{
|
||||
$this->createManifest();
|
||||
|
||||
$this->assertEquals([
|
||||
'build' => '1.0.0',
|
||||
'modified' => false,
|
||||
'confident' => true
|
||||
], $this->sourceManifest->compare($this->builds['1.0.0']));
|
||||
|
||||
$this->assertEquals([
|
||||
'build' => '1.0.1',
|
||||
'modified' => false,
|
||||
'confident' => true
|
||||
], $this->sourceManifest->compare($this->builds['1.0.1']));
|
||||
|
||||
$this->assertEquals([
|
||||
'build' => '1.0.2',
|
||||
'modified' => false,
|
||||
'confident' => true
|
||||
], $this->sourceManifest->compare($this->builds['1.0.2']));
|
||||
|
||||
$this->assertEquals([
|
||||
'build' => '1.0.3',
|
||||
'modified' => false,
|
||||
'confident' => true
|
||||
], $this->sourceManifest->compare($this->builds['1.0.3']));
|
||||
|
||||
$this->assertEquals([
|
||||
'build' => '1.1.0',
|
||||
'modified' => false,
|
||||
'confident' => true
|
||||
], $this->sourceManifest->compare($this->builds['1.1.0']));
|
||||
|
||||
$this->assertEquals([
|
||||
'build' => '1.1.1',
|
||||
'modified' => false,
|
||||
'confident' => true
|
||||
], $this->sourceManifest->compare($this->builds['1.1.1']));
|
||||
}
|
||||
|
||||
public function testCompareModified()
|
||||
{
|
||||
$this->createManifest();
|
||||
|
||||
// Hot-swap "tests/fixtures/manifest/1_1_1/modules/test/file3.php"
|
||||
$old = file_get_contents(base_path('modules/system/tests/fixtures/manifest/1_1_1/modules/test/file3.php'));
|
||||
file_put_contents(base_path('modules/system/tests/fixtures/manifest/1_1_1/modules/test/file3.php'), '<?php // Changed');
|
||||
|
||||
$modifiedManifest = new FileManifest(base_path('modules/system/tests/fixtures/manifest/1_1_1'), ['test', 'test2']);
|
||||
$modifiedManifest->getFiles();
|
||||
|
||||
file_put_contents(base_path('modules/system/tests/fixtures/manifest/1_1_1/modules/test/file3.php'), $old);
|
||||
|
||||
$this->assertEquals([
|
||||
'build' => '1.1.1',
|
||||
'modified' => true,
|
||||
'confident' => true,
|
||||
], $this->sourceManifest->compare($modifiedManifest));
|
||||
}
|
||||
|
||||
public function testCompareModifiedSecondBranch()
|
||||
{
|
||||
$this->createManifest();
|
||||
|
||||
// Add "tests/fixtures/manifest/1_0_3/modules/test/file3.php"
|
||||
file_put_contents(base_path('modules/system/tests/fixtures/manifest/1_0_3/modules/test/file3.php'), '<?php // Changed');
|
||||
|
||||
$modifiedManifest = new FileManifest(base_path('modules/system/tests/fixtures/manifest/1_0_3'), ['test', 'test2']);
|
||||
$modifiedManifest->getFiles();
|
||||
|
||||
unlink(base_path('modules/system/tests/fixtures/manifest/1_0_3/modules/test/file3.php'));
|
||||
|
||||
$this->assertEquals([
|
||||
'build' => '1.0.3',
|
||||
'modified' => true,
|
||||
'confident' => false, // 50% match, not confident
|
||||
], $this->sourceManifest->compare($modifiedManifest));
|
||||
}
|
||||
|
||||
protected function createManifest(bool $write = false)
|
||||
{
|
||||
$this->deleteManifest();
|
||||
|
||||
foreach ($this->builds as $build => $fileManifest) {
|
||||
$this->sourceManifest->addBuild($build, $fileManifest);
|
||||
}
|
||||
|
||||
if ($write) {
|
||||
file_put_contents($this->manifestPath(), $this->sourceManifest->generate());
|
||||
}
|
||||
|
||||
$this->sourceManifest->loadForks();
|
||||
}
|
||||
|
||||
protected function deleteManifest()
|
||||
{
|
||||
if (file_exists($this->manifestPath())) {
|
||||
unlink($this->manifestPath());
|
||||
}
|
||||
}
|
||||
|
||||
protected function manifestPath()
|
||||
{
|
||||
return base_path('modules/system/tests/fixtures/manifest/builds.json');
|
||||
}
|
||||
|
||||
protected function forksPath()
|
||||
{
|
||||
return base_path('modules/system/tests/fixtures/manifest/forks.json');
|
||||
}
|
||||
}
|
||||
258
modules/system/tests/classes/VersionManagerTest.php
Normal file
258
modules/system/tests/classes/VersionManagerTest.php
Normal file
@@ -0,0 +1,258 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Classes;
|
||||
|
||||
use System\Tests\Bootstrap\TestCase;
|
||||
use System\Classes\VersionManager;
|
||||
|
||||
class VersionManagerTest extends TestCase
|
||||
{
|
||||
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
include_once base_path() . '/modules/system/tests/fixtures/plugins/winter/tester/Plugin.php';
|
||||
include_once base_path() . '/modules/system/tests/fixtures/plugins/winter/sample/Plugin.php';
|
||||
include_once base_path() . '/modules/system/tests/fixtures/plugins/winter/noupdates/Plugin.php';
|
||||
}
|
||||
|
||||
//
|
||||
// Tests
|
||||
//
|
||||
|
||||
public function testGetLatestFileVersion()
|
||||
{
|
||||
$manager = VersionManager::instance();
|
||||
$result = self::callProtectedMethod($manager, 'getLatestFileVersion', ['\Winter\\Tester']);
|
||||
|
||||
$this->assertNotNull($result);
|
||||
$this->assertEquals('1.5.1', $result);
|
||||
}
|
||||
|
||||
public function testGetFileVersions()
|
||||
{
|
||||
$manager = VersionManager::instance();
|
||||
$result = self::callProtectedMethod($manager, 'getFileVersions', ['\Winter\\Tester']);
|
||||
|
||||
$this->assertCount(13, $result);
|
||||
$this->assertArrayHasKey('1.0.1', $result);
|
||||
$this->assertArrayHasKey('1.0.2', $result);
|
||||
$this->assertArrayHasKey('1.0.3', $result);
|
||||
$this->assertArrayHasKey('1.0.4', $result);
|
||||
$this->assertArrayHasKey('1.0.5', $result);
|
||||
$this->assertArrayHasKey('1.1.0', $result);
|
||||
$this->assertArrayHasKey('1.2.0', $result);
|
||||
$this->assertArrayHasKey('1.3.0', $result);
|
||||
$this->assertArrayHasKey('1.3.1', $result);
|
||||
$this->assertArrayHasKey('1.3.2', $result);
|
||||
$this->assertArrayHasKey('1.4.1', $result);
|
||||
$this->assertArrayHasKey('1.5.0', $result);
|
||||
$this->assertArrayHasKey('1.5.1', $result);
|
||||
|
||||
$sample = $result['1.0.1'];
|
||||
$this->assertEquals('Added some upgrade file and some "seeding"', $sample[0]);
|
||||
|
||||
$sample = $result['1.1.0'];
|
||||
$this->assertEquals('!!! Drop support for blog settings', $sample[0]);
|
||||
$this->assertEquals('drop_blog_settings_table.php', $sample[1]);
|
||||
|
||||
$sample = $result['1.2.0'];
|
||||
$this->assertEquals('!!! Security update - see: https://wintercms.com', $sample[0]);
|
||||
|
||||
$sample = $result['1.3.0'];
|
||||
$this->assertEquals('!!! We\'ve refactored major parts of this plugin. Please see the website for more information.', $sample);
|
||||
|
||||
$sample = $result['1.3.1'];
|
||||
$this->assertEquals('Minor bug fix Please see changelog', $sample[0]);
|
||||
$this->assertEquals('fix_database.php', $sample[1]);
|
||||
|
||||
$sample = $result['1.3.2'];
|
||||
$this->assertEquals('Added support for Translate plugin. Added some new languages.', $sample);
|
||||
|
||||
$sample = $result['1.5.0'];
|
||||
$this->assertEquals('!!! Another major update to fix several issues', $sample);
|
||||
|
||||
$sample = $result['1.5.1'];
|
||||
$this->assertEquals('Improved signature with the Test::method()', $sample[0]);
|
||||
$this->assertEquals('Translation updates.', $sample[1]);
|
||||
|
||||
/*
|
||||
* Test junk file
|
||||
*/
|
||||
$result = self::callProtectedMethod($manager, 'getFileVersions', ['\Winter\\Sample']);
|
||||
$this->assertCount(5, $result);
|
||||
$this->assertArrayHasKey('junk', $result);
|
||||
$this->assertArrayHasKey('1', $result);
|
||||
$this->assertArrayHasKey('1.0.*', $result);
|
||||
$this->assertArrayHasKey('1.0.x', $result);
|
||||
$this->assertArrayHasKey('10.3', $result);
|
||||
|
||||
$sample = array_shift($result);
|
||||
$comment = array_shift($sample);
|
||||
$this->assertEquals("JUNK JUNK JUNK", $comment);
|
||||
|
||||
/*
|
||||
* Test empty file
|
||||
*/
|
||||
$result = self::callProtectedMethod($manager, 'getFileVersions', ['\Winter\\NoUpdates']);
|
||||
$this->assertEmpty($result);
|
||||
}
|
||||
|
||||
public function testGetNewFileVersions()
|
||||
{
|
||||
$manager = VersionManager::instance();
|
||||
$result = self::callProtectedMethod($manager, 'getNewFileVersions', ['\Winter\\Tester', '1.0.3']);
|
||||
|
||||
$this->assertCount(10, $result);
|
||||
$this->assertArrayHasKey('1.0.4', $result);
|
||||
$this->assertArrayHasKey('1.0.5', $result);
|
||||
$this->assertArrayHasKey('1.1.0', $result);
|
||||
$this->assertArrayHasKey('1.2.0', $result);
|
||||
$this->assertArrayHasKey('1.3.0', $result);
|
||||
$this->assertArrayHasKey('1.3.1', $result);
|
||||
$this->assertArrayHasKey('1.3.2', $result);
|
||||
$this->assertArrayHasKey('1.4.1', $result);
|
||||
$this->assertArrayHasKey('1.5.0', $result);
|
||||
$this->assertArrayHasKey('1.5.1', $result);
|
||||
|
||||
/*
|
||||
* When at version 0, should return everything
|
||||
*/
|
||||
$manager = VersionManager::instance();
|
||||
$result = self::callProtectedMethod($manager, 'getNewFileVersions', ['\Winter\\Tester']);
|
||||
|
||||
$this->assertCount(13, $result);
|
||||
$this->assertArrayHasKey('1.0.1', $result);
|
||||
$this->assertArrayHasKey('1.0.2', $result);
|
||||
$this->assertArrayHasKey('1.0.3', $result);
|
||||
$this->assertArrayHasKey('1.0.4', $result);
|
||||
$this->assertArrayHasKey('1.0.5', $result);
|
||||
$this->assertArrayHasKey('1.1.0', $result);
|
||||
$this->assertArrayHasKey('1.2.0', $result);
|
||||
$this->assertArrayHasKey('1.3.0', $result);
|
||||
$this->assertArrayHasKey('1.3.1', $result);
|
||||
$this->assertArrayHasKey('1.3.2', $result);
|
||||
$this->assertArrayHasKey('1.4.1', $result);
|
||||
$this->assertArrayHasKey('1.5.0', $result);
|
||||
$this->assertArrayHasKey('1.5.1', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider versionInfoProvider
|
||||
*
|
||||
* @param $versionInfo
|
||||
* @param $expectedComments
|
||||
* @param $expectedScripts
|
||||
*/
|
||||
public function testExtractScriptsAndComments($versionInfo, $expectedComments, $expectedScripts)
|
||||
{
|
||||
$manager = VersionManager::instance();
|
||||
list($comments, $scripts) = self::callProtectedMethod($manager, 'extractScriptsAndComments', [$versionInfo]);
|
||||
|
||||
$this->assertIsArray($comments);
|
||||
$this->assertIsArray($scripts);
|
||||
|
||||
$this->assertEquals($expectedComments, $comments);
|
||||
$this->assertEquals($expectedScripts, $scripts);
|
||||
}
|
||||
|
||||
public function versionInfoProvider()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'A single update comment string',
|
||||
[
|
||||
'A single update comment string'
|
||||
],
|
||||
[]
|
||||
],
|
||||
[
|
||||
[
|
||||
'A classic update comment string followed by script',
|
||||
'update_script.php'
|
||||
],
|
||||
[
|
||||
'A classic update comment string followed by script'
|
||||
],
|
||||
[
|
||||
'update_script.php'
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
'scripts_can_go_first.php',
|
||||
'An update comment string after the script',
|
||||
],
|
||||
[
|
||||
'An update comment string after the script'
|
||||
],
|
||||
[
|
||||
'scripts_can_go_first.php'
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
'scripts_can_go_first.php',
|
||||
'An update comment string after the script',
|
||||
'scripts_can_go_anywhere.php',
|
||||
],
|
||||
[
|
||||
'An update comment string after the script'
|
||||
],
|
||||
[
|
||||
'scripts_can_go_first.php',
|
||||
'scripts_can_go_anywhere.php'
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
'scripts_can_go_first.php',
|
||||
'The first update comment',
|
||||
'scripts_can_go_anywhere.php',
|
||||
'The second update comment',
|
||||
],
|
||||
[
|
||||
'The first update comment',
|
||||
'The second update comment'
|
||||
],
|
||||
[
|
||||
'scripts_can_go_first.php',
|
||||
'scripts_can_go_anywhere.php'
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
'file.name.with.dots.php',
|
||||
'The first update comment',
|
||||
'1.0.2.scripts_can_go_anywhere.php',
|
||||
'The second update comment',
|
||||
],
|
||||
[
|
||||
'The first update comment',
|
||||
'The second update comment'
|
||||
],
|
||||
[
|
||||
'file.name.with.dots.php',
|
||||
'1.0.2.scripts_can_go_anywhere.php'
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
'subdirectory/file.name.with.dots.php',
|
||||
'The first update comment',
|
||||
'subdirectory\1.0.2.scripts_can_go_anywhere.php',
|
||||
'The second update comment',
|
||||
],
|
||||
[
|
||||
'The first update comment',
|
||||
'The second update comment'
|
||||
],
|
||||
[
|
||||
'subdirectory/file.name.with.dots.php',
|
||||
'subdirectory\1.0.2.scripts_can_go_anywhere.php'
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
232
modules/system/tests/classes/asset/BundleManagerTest.php
Normal file
232
modules/system/tests/classes/asset/BundleManagerTest.php
Normal file
@@ -0,0 +1,232 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Classes\Asset;
|
||||
|
||||
use System\Classes\Asset\BundleManager;
|
||||
use System\Tests\Bootstrap\TestCase;
|
||||
|
||||
class BundleManagerTest extends TestCase
|
||||
{
|
||||
protected BundleManager $bundleManager;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
// Reset the bundle manager
|
||||
BundleManager::forgetInstance();
|
||||
// Bind the instance for convenience
|
||||
$this->bundleManager = BundleManager::instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the registerBundles & registerBundle functions correctly allow the user to append bundles
|
||||
*/
|
||||
public function testRegisterBundles(): void
|
||||
{
|
||||
$defaultBundles = $this->bundleManager->getBundles();
|
||||
$this->bundleManager->registerBundles([
|
||||
'winter1js' => [
|
||||
'winter1js' => 'v1.0.0'
|
||||
]
|
||||
]);
|
||||
|
||||
$this->bundleManager->registerBundle('winter2js', [
|
||||
'winter2js' => 'v1.0.0'
|
||||
]);
|
||||
|
||||
$bundles = $this->bundleManager->getBundles();
|
||||
$this->assertCount(count($defaultBundles) + 2, $bundles);
|
||||
$this->assertContains('winter1js', $bundles);
|
||||
$this->assertContains('winter2js', $bundles);
|
||||
}
|
||||
|
||||
/**
|
||||
* This test ensures that defining new bundles does not affect the default bundles
|
||||
*/
|
||||
public function testRegisterBundlesDoesNotBreakDefaults(): void
|
||||
{
|
||||
// Get the default bundles so we can validate them existing later
|
||||
$defaultBundles = $this->bundleManager->getBundles();
|
||||
// Flush the instance as if we have just booted
|
||||
BundleManager::forgetInstance();
|
||||
$this->bundleManager = BundleManager::instance();
|
||||
// Register a new bundle
|
||||
$this->bundleManager->registerBundles([
|
||||
'winterjs' => [
|
||||
'winterjs' => 'v1.0.0'
|
||||
]
|
||||
]);
|
||||
// Grab the current bundles
|
||||
$bundles = $this->bundleManager->getBundles();
|
||||
// Validate that all default bundles have been registered when adding a new bundle
|
||||
foreach ($defaultBundles as $defaultBundle) {
|
||||
$this->assertContains($defaultBundle, $bundles);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the forcing a package to a new version
|
||||
*/
|
||||
public function testRegisterBundlesOverrideDefault(): void
|
||||
{
|
||||
$tailwindPackages = $this->bundleManager->getBundlePackages('tailwind', 'mix');
|
||||
|
||||
$this->bundleManager->registerBundle('tailwind', [
|
||||
'tailwindcss' => 'dev-999.999.999',
|
||||
'@tailwindcss/forms' => 'dev-999.999.999',
|
||||
'@tailwindcss/typography' => 'dev-999.999.999',
|
||||
]);
|
||||
|
||||
$updatedTailwindPackages = $this->bundleManager->getBundlePackages('tailwind', 'mix');
|
||||
|
||||
foreach ($tailwindPackages as $tailwindPackage => $version) {
|
||||
$this->assertArrayHasKey($tailwindPackage, $updatedTailwindPackages);
|
||||
$this->assertNotEquals($updatedTailwindPackages[$tailwindPackage], $version);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting all supported bundles
|
||||
*/
|
||||
public function testGetBundles(): void
|
||||
{
|
||||
$bundles = $this->bundleManager->getBundles();
|
||||
|
||||
$this->assertIsArray($bundles);
|
||||
$count = count($bundles);
|
||||
|
||||
$this->bundleManager->registerBundle('test', [
|
||||
'a' => 'v0.1.2',
|
||||
]);
|
||||
|
||||
$this->assertCount($count + 1, $this->bundleManager->getBundles());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting bundle packages works and allows for config overloading
|
||||
*/
|
||||
public function testGetBundlePackages(): void
|
||||
{
|
||||
// Test that getting a default returns an array and validate one of the packages
|
||||
$packages = $this->bundleManager->getBundlePackages('tailwind', 'mix');
|
||||
$this->assertIsArray($packages);
|
||||
$this->assertArrayHasKey('tailwindcss', $packages);
|
||||
|
||||
// Test that getting a package with compiler dependant packages does not return the package for invalid compiler
|
||||
$packages = $this->bundleManager->getBundlePackages('vue', 'mix');
|
||||
$this->assertIsArray($packages);
|
||||
$this->assertArrayNotHasKey('@vitejs/plugin-vue', $packages);
|
||||
|
||||
// Test that getting a package with compiler dependant packages does return the package for a valid compiler
|
||||
$packages = $this->bundleManager->getBundlePackages('vue', 'vite');
|
||||
$this->assertIsArray($packages);
|
||||
$this->assertArrayHasKey('@vitejs/plugin-vue', $packages);
|
||||
|
||||
// Validate that `testing` does not exist
|
||||
$packages = $this->bundleManager->getBundlePackages('testing', 'vite');
|
||||
$this->assertIsArray($packages);
|
||||
$this->assertEmpty($packages);
|
||||
|
||||
$this->bundleManager->registerBundle('testing', [
|
||||
'a' => 'v0.1.2',
|
||||
'mix' => [
|
||||
'b' => 'v0.1.3',
|
||||
]
|
||||
]);
|
||||
|
||||
// Validate the testing bundle works with compiler dependent packages
|
||||
$packages = $this->bundleManager->getBundlePackages('testing', 'vite');
|
||||
$this->assertIsArray($packages);
|
||||
$this->assertCount(1, $packages);
|
||||
|
||||
$packages = $this->bundleManager->getBundlePackages('testing', 'mix');
|
||||
$this->assertIsArray($packages);
|
||||
$this->assertCount(2, $packages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the AssetBundles setup handlers functionality
|
||||
*/
|
||||
public function testSetupHandlers(): void
|
||||
{
|
||||
// Test that the default handler is accessible
|
||||
$handler = $this->bundleManager->getSetupHandler('tailwind');
|
||||
$this->assertIsCallable($handler);
|
||||
|
||||
// Add a new handler
|
||||
$this->bundleManager->registerSetupHandler('testing', fn () => true);
|
||||
$handler = $this->bundleManager->getSetupHandler('testing');
|
||||
$this->assertIsCallable($handler);
|
||||
|
||||
// Validate that handler returned is ours
|
||||
$this->assertTrue($handler());
|
||||
|
||||
// Override the handler
|
||||
$this->bundleManager->registerSetupHandler('testing', fn () => false);
|
||||
$handler = $this->bundleManager->getSetupHandler('testing');
|
||||
$this->assertIsCallable($handler);
|
||||
$this->assertFalse($handler());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the AssetBundles scaffold handlers functionality
|
||||
*/
|
||||
public function testScaffoldHandlers(): void
|
||||
{
|
||||
// Test that the default handler is accessible
|
||||
$handler = $this->bundleManager->getScaffoldHandler('tailwind');
|
||||
$this->assertIsCallable($handler);
|
||||
|
||||
// Add a new handler
|
||||
$this->bundleManager->registerScaffoldHandler('testing', fn () => true);
|
||||
$handler = $this->bundleManager->getScaffoldHandler('testing');
|
||||
$this->assertIsCallable($handler);
|
||||
|
||||
// Validate that handler returned is ours
|
||||
$this->assertTrue($handler());
|
||||
|
||||
// Override the handler
|
||||
$this->bundleManager->registerScaffoldHandler('testing', fn () => false);
|
||||
$handler = $this->bundleManager->getScaffoldHandler('testing');
|
||||
$this->assertIsCallable($handler);
|
||||
$this->assertFalse($handler());
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that when registered a callable is added to the `callbacks` array within the BundleManager
|
||||
*/
|
||||
public function testRegisterCallback(): void
|
||||
{
|
||||
$this->expectExceptionMessage('callback registered');
|
||||
$this->bundleManager->registerCallback(function (BundleManager $manager) {
|
||||
throw new \RuntimeException('callback registered');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that calling registerBundles within registerCallback functions correctly
|
||||
*/
|
||||
public function testLoadRegisteredBundles(): void
|
||||
{
|
||||
$this->bundleManager->registerCallback(function (BundleManager $manager) {
|
||||
$manager->registerBundles([
|
||||
'winter-test-js' => [
|
||||
'test-package' => 'v0.1.2',
|
||||
'vite' => [
|
||||
'vite-package' => 'v0.1.3',
|
||||
]
|
||||
]
|
||||
]);
|
||||
});
|
||||
|
||||
$this->assertContains('winter-test-js', $this->bundleManager->getBundles());
|
||||
|
||||
$bundle = $this->bundleManager->getBundlePackages('winter-test-js', 'mix');
|
||||
$this->assertArrayHasKey('test-package', $bundle);
|
||||
$this->assertArrayNotHasKey('vite-package', $bundle);
|
||||
|
||||
$bundle = $this->bundleManager->getBundlePackages('winter-test-js', 'vite');
|
||||
$this->assertArrayHasKey('test-package', $bundle);
|
||||
$this->assertArrayHasKey('vite-package', $bundle);
|
||||
}
|
||||
}
|
||||
469
modules/system/tests/classes/asset/PackageJsonTest.php
Normal file
469
modules/system/tests/classes/asset/PackageJsonTest.php
Normal file
@@ -0,0 +1,469 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Classes\Asset;
|
||||
|
||||
use System\Classes\Asset\PackageJson;
|
||||
use System\Tests\Bootstrap\TestCase;
|
||||
|
||||
class PackageJsonTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Default test file fixture
|
||||
*/
|
||||
protected string $testFile;
|
||||
|
||||
/**
|
||||
* Bind the default test file fixture
|
||||
*/
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->testFile = __DIR__ . '/../../fixtures/npm/package-test.json';
|
||||
}
|
||||
|
||||
/**
|
||||
* Test loading a package.json file from path
|
||||
*/
|
||||
public function testLoadFile(): void
|
||||
{
|
||||
$packageJson = new PackageJson($this->testFile);
|
||||
$contents = $packageJson->getContents();
|
||||
|
||||
$this->assertArrayHasKey('workspaces', $contents);
|
||||
$this->assertArrayHasKey('packages', $contents['workspaces']);
|
||||
$this->assertIsArray($contents['workspaces']['packages']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test loading a corrupted package.json file correctly errors
|
||||
*/
|
||||
public function testLoadCorruptFile(): void
|
||||
{
|
||||
$this->expectException(\JsonException::class);
|
||||
new PackageJson(__DIR__ . '/../../fixtures/npm/package-corrupt.json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creating an instance with non-existing file
|
||||
*/
|
||||
public function testNewFile(): void
|
||||
{
|
||||
$packageJson = new PackageJson(__DIR__ . '/../fixtures/npm/package-test-new.json');
|
||||
$contents = $packageJson->getContents();
|
||||
$this->assertIsArray($contents);
|
||||
$this->assertCount(0, $contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creating an instance without a path
|
||||
*/
|
||||
public function testMemoryInstance(): void
|
||||
{
|
||||
$packageJson = new PackageJson();
|
||||
$contents = $packageJson->getContents();
|
||||
$this->assertIsArray($contents);
|
||||
$this->assertCount(0, $contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test setting and getting the name property
|
||||
*/
|
||||
public function testNameMethods(): void
|
||||
{
|
||||
$packageJson = new PackageJson();
|
||||
$contents = $packageJson->getContents();
|
||||
$this->assertIsArray($contents);
|
||||
$this->assertCount(0, $contents);
|
||||
|
||||
$packageJson->setName('example-name');
|
||||
|
||||
$this->assertEquals('example-name', $packageJson->getName());
|
||||
|
||||
$contents = $packageJson->getContents();
|
||||
$this->assertIsArray($contents);
|
||||
$this->assertCount(1, $contents);
|
||||
$this->assertArrayHasKey('name', $contents);
|
||||
$this->assertEquals('example-name', $contents['name']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting the path of the current file
|
||||
*/
|
||||
public function testGetPath(): void
|
||||
{
|
||||
$packageJson = new PackageJson(__DIR__ . '/package.json');
|
||||
$path = $packageJson->getPath();
|
||||
$this->assertIsString($path);
|
||||
$this->assertEquals(__DIR__ . '/package.json', $path);
|
||||
|
||||
$packageJson = new PackageJson();
|
||||
$path = $packageJson->getPath();
|
||||
$this->assertNull($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test validating the name on set
|
||||
*/
|
||||
public function testNameValidation(): void
|
||||
{
|
||||
$packageJson = new PackageJson();
|
||||
|
||||
$this->assertThrows(function () use ($packageJson) {
|
||||
$packageJson->setName('Test');
|
||||
}, \InvalidArgumentException::class, 'Package names must be lower case');
|
||||
|
||||
$this->assertThrows(function () use ($packageJson) {
|
||||
$packageJson->setName('.test');
|
||||
}, \InvalidArgumentException::class, 'Package names must not start with . or _');
|
||||
|
||||
$this->assertThrows(function () use ($packageJson) {
|
||||
$packageJson->setName('_test');
|
||||
}, \InvalidArgumentException::class, 'Package names must not start with . or _');
|
||||
|
||||
$this->assertThrows(function () use ($packageJson) {
|
||||
$packageJson->setName('te~st');
|
||||
}, \InvalidArgumentException::class, 'Package names must not include special characters');
|
||||
|
||||
$this->assertThrows(function () use ($packageJson) {
|
||||
$packageJson->setName('te*st');
|
||||
}, \InvalidArgumentException::class, 'Package names must not include special characters');
|
||||
|
||||
$this->assertThrows(function () use ($packageJson) {
|
||||
$packageJson->setName('test!');
|
||||
}, \InvalidArgumentException::class, 'Package names must not include special characters');
|
||||
|
||||
$this->assertThrows(function () use ($packageJson) {
|
||||
$packageJson->setName(sprintf('te%sst', str_repeat('s', 214)));
|
||||
}, \InvalidArgumentException::class, 'Package names must not be longer than 214 characters');
|
||||
|
||||
$this->assertThrows(function () use ($packageJson) {
|
||||
$packageJson->setName('test ');
|
||||
}, \InvalidArgumentException::class, 'Package names must not include whitespace');
|
||||
|
||||
$this->assertThrows(function () use ($packageJson) {
|
||||
$packageJson->setName(' test');
|
||||
}, \InvalidArgumentException::class, 'Package names must not include whitespace');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test checking package workspace exists
|
||||
*/
|
||||
public function testHasWorkspace(): void
|
||||
{
|
||||
$packageJson = new PackageJson($this->testFile);
|
||||
$this->assertTrue($packageJson->hasWorkspace('themes/demo'));
|
||||
$this->assertFalse($packageJson->hasWorkspace('themes/test'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test adding workspace package
|
||||
*/
|
||||
public function testAddWorkspace(): void
|
||||
{
|
||||
$packageJson = new PackageJson($this->testFile);
|
||||
$this->assertFalse($packageJson->hasWorkspace('themes/test'));
|
||||
$packageJson->addWorkspace('themes/test');
|
||||
$this->assertTrue($packageJson->hasWorkspace('themes/test'));
|
||||
|
||||
// Create blank source
|
||||
$packageJson = new PackageJson();
|
||||
$this->assertFalse($packageJson->hasWorkspace('themes/test'));
|
||||
$packageJson->addWorkspace('themes/test');
|
||||
$this->assertTrue($packageJson->hasWorkspace('themes/test'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test removing workspace package
|
||||
*/
|
||||
public function testRemoveWorkspace(): void
|
||||
{
|
||||
$packageJson = new PackageJson($this->testFile);
|
||||
$this->assertTrue($packageJson->hasWorkspace('themes/demo'));
|
||||
$packageJson->removeWorkspace('themes/demo');
|
||||
$this->assertFalse($packageJson->hasWorkspace('themes/demo'));
|
||||
|
||||
// Create blank source
|
||||
$packageJson = new PackageJson();
|
||||
$packageJson->removeWorkspace('themes/demo');
|
||||
$this->assertFalse($packageJson->hasWorkspace('themes/demo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test when adding a workspace package, it removes the package from ignored workspace packages
|
||||
*/
|
||||
public function testAddWorkspaceRemovesIgnoredPackage(): void
|
||||
{
|
||||
$packageJson = new PackageJson($this->testFile);
|
||||
$this->assertFalse($packageJson->hasWorkspace('modules/backend'));
|
||||
$this->assertTrue($packageJson->hasIgnoredPackage('modules/backend'));
|
||||
|
||||
$packageJson->addWorkspace('modules/backend');
|
||||
|
||||
$this->assertTrue($packageJson->hasWorkspace('modules/backend'));
|
||||
$this->assertFalse($packageJson->hasIgnoredPackage('modules/backend'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test checking ignore package workspace exists
|
||||
*/
|
||||
public function testHasIgnoredPackage(): void
|
||||
{
|
||||
$packageJson = new PackageJson($this->testFile);
|
||||
$this->assertTrue($packageJson->hasIgnoredPackage('modules/backend'));
|
||||
$this->assertFalse($packageJson->hasIgnoredPackage('modules/test'));
|
||||
|
||||
// Create blank source
|
||||
$packageJson = new PackageJson();
|
||||
$this->assertFalse($packageJson->hasIgnoredPackage('modules/backend'));
|
||||
$this->assertFalse($packageJson->hasIgnoredPackage('modules/test'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test adding ignore workspace package
|
||||
*/
|
||||
public function testAddIgnoredPackage(): void
|
||||
{
|
||||
$packageJson = new PackageJson($this->testFile);
|
||||
$this->assertFalse($packageJson->hasIgnoredPackage('themes/example'));
|
||||
$packageJson->addIgnoredPackage('themes/example');
|
||||
$this->assertTrue($packageJson->hasIgnoredPackage('themes/example'));
|
||||
|
||||
// Create blank source
|
||||
$packageJson = new PackageJson();
|
||||
$packageJson->addIgnoredPackage('themes/example');
|
||||
$this->assertTrue($packageJson->hasIgnoredPackage('themes/example'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test removing ignore workspace package
|
||||
*/
|
||||
public function testRemoveIgnoredPackage(): void
|
||||
{
|
||||
$packageJson = new PackageJson($this->testFile);
|
||||
$this->assertTrue($packageJson->hasIgnoredPackage('modules/system'));
|
||||
$packageJson->removeIgnoredPackage('modules/system');
|
||||
$this->assertFalse($packageJson->hasIgnoredPackage('modules/system'));
|
||||
|
||||
// Create blank source
|
||||
$packageJson = new PackageJson();
|
||||
$packageJson->removeIgnoredPackage('modules/system');
|
||||
$this->assertFalse($packageJson->hasIgnoredPackage('modules/system'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test when adding an ignore workspace package, it removes the package from workspace packages
|
||||
*/
|
||||
public function testAddIgnoredPackageRemovesWorkspace(): void
|
||||
{
|
||||
$packageJson = new PackageJson($this->testFile);
|
||||
$this->assertTrue($packageJson->hasWorkspace('themes/demo'));
|
||||
$this->assertFalse($packageJson->hasIgnoredPackage('themes/demo'));
|
||||
|
||||
$packageJson->addIgnoredPackage('themes/demo');
|
||||
|
||||
$this->assertFalse($packageJson->hasWorkspace('themes/demo'));
|
||||
$this->assertTrue($packageJson->hasIgnoredPackage('themes/demo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test checking if package.json has deps
|
||||
*/
|
||||
public function testHasDependency(): void
|
||||
{
|
||||
$packageJson = new PackageJson($this->testFile);
|
||||
// Check that deps exist
|
||||
$this->assertTrue($packageJson->hasDependency('test'));
|
||||
$this->assertTrue($packageJson->hasDependency('test-dev'));
|
||||
// Check that deps don't exist
|
||||
$this->assertFalse($packageJson->hasWorkspace('test-dev2'));
|
||||
$this->assertFalse($packageJson->hasWorkspace('testx'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test adding dependencies, when overwriting check that package is moved from devDeps to deps or revsersed
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testAddDependency(): void
|
||||
{
|
||||
// Test adding packages
|
||||
$packageJson = new PackageJson($this->testFile);
|
||||
|
||||
$packageJson->addDependency('winter', '4.0.1', dev: false)
|
||||
->addDependency('winter-dev', '4.0.1', dev: true);
|
||||
|
||||
$this->assertArrayNotHasKey('winter', $packageJson->getContents()['devDependencies']);
|
||||
$this->assertArrayHasKey('winter', $packageJson->getContents()['dependencies']);
|
||||
$this->assertArrayNotHasKey('winter-dev', $packageJson->getContents()['dependencies']);
|
||||
$this->assertArrayHasKey('winter-dev', $packageJson->getContents()['devDependencies']);
|
||||
|
||||
// Test adding packages with overwrites
|
||||
$packageJson = new PackageJson($this->testFile);
|
||||
|
||||
// Should do nothing as test is already in deps not dev deps
|
||||
$packageJson->addDependency('test', '6.0.1', dev: true, overwrite: false);
|
||||
|
||||
$this->assertArrayHasKey('test', $packageJson->getContents()['dependencies']);
|
||||
$this->assertArrayNotHasKey('test', $packageJson->getContents()['devDependencies']);
|
||||
$this->assertEquals('^1.0.0', $packageJson->getContents()['dependencies']['test']);
|
||||
|
||||
// Should move package from dev deps to deps with new version
|
||||
$packageJson->addDependency('test', '6.0.1', dev: true, overwrite: true);
|
||||
|
||||
$this->assertArrayNotHasKey('test', $packageJson->getContents()['dependencies']);
|
||||
$this->assertArrayHasKey('test', $packageJson->getContents()['devDependencies']);
|
||||
$this->assertEquals('6.0.1', $packageJson->getContents()['devDependencies']['test']);
|
||||
|
||||
// Create blank source
|
||||
$packageJson = new PackageJson();
|
||||
// Add a non-dev dependency
|
||||
$packageJson->addDependency('winter', '4.0.1', dev: false);
|
||||
// Add a dev dependency
|
||||
$packageJson->addDependency('winter-dev', '4.0.1', dev: true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test removing dependencies
|
||||
*/
|
||||
public function testRemoveDependency(): void
|
||||
{
|
||||
$packageJson = new PackageJson($this->testFile);
|
||||
|
||||
// Check package removed from dev deps
|
||||
$this->assertArrayHasKey('test-dev', $packageJson->getContents()['devDependencies'] ?? []);
|
||||
$packageJson->removeDependency('test-dev');
|
||||
$this->assertArrayNotHasKey('test-dev', $packageJson->getContents()['devDependencies'] ?? []);
|
||||
|
||||
// Check package removed from deps
|
||||
$this->assertArrayHasKey('test', $packageJson->getContents()['dependencies'] ?? []);
|
||||
$packageJson->removeDependency('test');
|
||||
$this->assertArrayNotHasKey('test', $packageJson->getContents()['dependencies'] ?? []);
|
||||
|
||||
// Create blank source
|
||||
$packageJson = new PackageJson();
|
||||
$packageJson->removeDependency('test-dev');
|
||||
$this->assertArrayNotHasKey('test-dev', $packageJson->getContents()['devDependencies'] ?? []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test checking if a script exists in a package.json
|
||||
*/
|
||||
public function testHasScript(): void
|
||||
{
|
||||
$packageJson = new PackageJson($this->testFile);
|
||||
|
||||
$this->assertTrue($packageJson->hasScript('foo'));
|
||||
$this->assertTrue($packageJson->hasScript('example'));
|
||||
$this->assertTrue($packageJson->hasScript('test'));
|
||||
|
||||
$this->assertFalse($packageJson->hasScript('bar'));
|
||||
$this->assertFalse($packageJson->hasScript('winter'));
|
||||
$this->assertFalse($packageJson->hasScript('testing'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting the value of a script by name
|
||||
*/
|
||||
public function testGetScript(): void
|
||||
{
|
||||
$packageJson = new PackageJson($this->testFile);
|
||||
|
||||
$this->assertEquals('bar ./test', $packageJson->getScript('foo'));
|
||||
$this->assertEquals('example test', $packageJson->getScript('example'));
|
||||
$this->assertEquals('testing', $packageJson->getScript('test'));
|
||||
|
||||
$packageJson = new PackageJson();
|
||||
$this->assertNull($packageJson->getScript('foo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting the value of a script by name
|
||||
*/
|
||||
public function testAddScript(): void
|
||||
{
|
||||
$packageJson = new PackageJson($this->testFile);
|
||||
|
||||
$packageJson->addScript('winter', 'winter ./testing');
|
||||
|
||||
$this->assertTrue($packageJson->hasScript('winter'));
|
||||
$this->assertEquals('winter ./testing', $packageJson->getScript('winter'));
|
||||
|
||||
$contents = $packageJson->getContents();
|
||||
|
||||
$this->assertTrue(isset($contents['scripts']['winter']));
|
||||
$this->assertEquals('winter ./testing', $contents['scripts']['winter']);
|
||||
|
||||
$packageJson = new PackageJson();
|
||||
$packageJson->addScript('winter', 'winter ./testing');
|
||||
$this->assertTrue($packageJson->hasScript('winter'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test removing scripts from package.json
|
||||
*/
|
||||
public function testRemoveScript(): void
|
||||
{
|
||||
$packageJson = new PackageJson($this->testFile);
|
||||
|
||||
$this->assertTrue($packageJson->hasScript('foo'));
|
||||
$packageJson->removeScript('foo');
|
||||
$this->assertFalse($packageJson->hasScript('foo'));
|
||||
|
||||
$this->assertTrue($packageJson->hasScript('example'));
|
||||
$packageJson->removeScript('example');
|
||||
$this->assertFalse($packageJson->hasScript('example'));
|
||||
|
||||
|
||||
$packageJson = new PackageJson();
|
||||
$packageJson->removeScript('foo');
|
||||
$this->assertFalse($packageJson->hasScript('foo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test saving, when saving with a file path set on init and passing a file path on save. Fails when no path given
|
||||
*/
|
||||
public function testSave(): void
|
||||
{
|
||||
$srcFile = $this->testFile;
|
||||
$backupFile = __DIR__ . '/../../fixtures/npm/package-test.json.back';
|
||||
|
||||
// Backup config file
|
||||
copy($srcFile, $backupFile);
|
||||
|
||||
// Make a change and save the file, overwriting
|
||||
$packageJson = new PackageJson($srcFile);
|
||||
$this->assertNull($packageJson->getName());
|
||||
$packageJson->setName('testing');
|
||||
$packageJson->save();
|
||||
|
||||
// Validate overwrite worked
|
||||
$packageJson = new PackageJson($srcFile);
|
||||
$this->assertEquals('testing', $packageJson->getName());
|
||||
|
||||
// Restore the config file
|
||||
copy($backupFile, $srcFile);
|
||||
// Remove backup file
|
||||
unlink($backupFile);
|
||||
|
||||
// Test saving file to new path
|
||||
$testFile = __DIR__ . '/../../fixtures/npm/package-test.json.test';
|
||||
$packageJson = new PackageJson($srcFile);
|
||||
$this->assertNull($packageJson->getName());
|
||||
$packageJson->setName('testing');
|
||||
$packageJson->save($testFile);
|
||||
|
||||
// Validate new file path exists and contains change
|
||||
$packageJson = new PackageJson($testFile);
|
||||
$this->assertEquals('testing', $packageJson->getName());
|
||||
|
||||
// Remove test file
|
||||
unlink($testFile);
|
||||
|
||||
// Validate that a file save with no path throws an error
|
||||
$this->assertThrows(function () {
|
||||
$packageJson = new PackageJson();
|
||||
$packageJson->setName('should-fail');
|
||||
$packageJson->save();
|
||||
}, \RuntimeException::class, 'Unable to save, no path given');
|
||||
}
|
||||
}
|
||||
44
modules/system/tests/console/CreateCommandTest.php
Normal file
44
modules/system/tests/console/CreateCommandTest.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Console;
|
||||
|
||||
use File;
|
||||
use InvalidArgumentException;
|
||||
use System\Tests\Bootstrap\TestCase;
|
||||
|
||||
class CreateCommandTest extends TestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->app->setPluginsPath(base_path() . '/modules/system/tests/fixtures/plugins/');
|
||||
}
|
||||
|
||||
public function testCreatingCommand()
|
||||
{
|
||||
$this->artisan('create:command Winter.Tester TestCommand')
|
||||
->assertExitCode(0);
|
||||
$this->artisan('create:command Winter.Tester Test1Command')
|
||||
->assertExitCode(0);
|
||||
|
||||
$this->artisan('create:command Winter.Tester4You TestCommand')
|
||||
->assertExitCode(0);
|
||||
$this->artisan('create:command Winter.Tester4You Test1Command')
|
||||
->assertExitCode(0);
|
||||
}
|
||||
|
||||
public function testNotCreatingCommandBeginingWithNumber()
|
||||
{
|
||||
$this->artisan('create:command Winter.Tester 1Command')->assertFailed();
|
||||
$this->artisan('create:command Winter.Tester4You 1Command')->assertFailed();
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
File::deleteDirectory(plugins_path('winter/tester/console'));
|
||||
File::deleteDirectory(plugins_path('winter/tester4you'));
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
}
|
||||
90
modules/system/tests/console/CreateMigrationTest.php
Normal file
90
modules/system/tests/console/CreateMigrationTest.php
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Console;
|
||||
|
||||
use File;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Schema;
|
||||
use System\Tests\Bootstrap\PluginTestCase;
|
||||
|
||||
class CreateMigrationTest extends PluginTestCase
|
||||
{
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->app->setPluginsPath(base_path() . '/modules/system/tests/fixtures/plugins/');
|
||||
|
||||
$this->table = 'winter_tester_test_model';
|
||||
$this->versionFile = plugins_path('winter/tester/updates/version.yaml');
|
||||
$this->versionFolder = plugins_path('winter/tester/updates/v0.0.1');
|
||||
|
||||
File::copy($this->versionFile, $this->versionFile . '.bak');
|
||||
}
|
||||
|
||||
public function testCreateMigration()
|
||||
{
|
||||
$this->artisan('create:migration Winter.Tester -c --force --for-version v0.0.1 --model TestModel --name create_table');
|
||||
$this->assertFileExists($this->versionFolder . '/create_table.php');
|
||||
|
||||
$migration = require_once $this->versionFolder . '/create_table.php';
|
||||
$migration->up();
|
||||
|
||||
$this->assertTrue(Schema::hasTable($this->table));
|
||||
|
||||
$columns = [
|
||||
'id' => ['type'=>'integer', 'index'=>'primary', 'required'=>true],
|
||||
'cb' => ['type'=>'boolean'],
|
||||
'switch' => ['type'=>'boolean'],
|
||||
'int' => ['type'=>'integer'],
|
||||
'uint' => ['type'=>'integer', 'required'=>true],
|
||||
'double' => ['type'=>'float'],
|
||||
'range' => ['type'=>'integer', 'required'=>true],
|
||||
'datetime' => ['type'=>'datetime'],
|
||||
'date' => ['type'=>'date', 'required'=>true],
|
||||
'time' => ['type'=>'time'],
|
||||
'md' => ['type'=>'text'],
|
||||
'textarea' => ['type'=>'text'],
|
||||
'text' => ['type'=>'string', 'required'=>true],
|
||||
'phone_id' => ['type'=>'integer', 'index'=>true, 'required'=>true],
|
||||
'user_id' => ['type'=>'integer', 'index'=>true, 'required'=>true],
|
||||
'data' => ['type'=>'text'],
|
||||
'sort_order' => ['type'=>'integer', 'index'=>true],
|
||||
'taggable_id' => ['type'=>'integer', 'index'=>'morphable_index'],
|
||||
'taggable_type' => ['type'=>'string', 'index'=>'morphable_index'],
|
||||
'created_at' => ['type'=>'datetime'],
|
||||
'updated_at' => ['type'=>'datetime'],
|
||||
];
|
||||
|
||||
$table = Schema::getConnection()->getDoctrineSchemaManager()->listTableDetails($this->table);
|
||||
|
||||
foreach ($columns as $name => $definition) {
|
||||
$this->assertEquals(array_get($definition, 'type'), Schema::getColumnType($this->table, $name));
|
||||
|
||||
// assert an index has been created for the primary, morph and foreign keys
|
||||
if ($indexName = array_get($definition, 'index')) {
|
||||
if ($indexName === true) {
|
||||
$indexName = sprintf("%s_%s_index", $this->table, $name);
|
||||
}
|
||||
$this->assertTrue($table->hasIndex($indexName));
|
||||
|
||||
if ($indexName === 'morphable_index') {
|
||||
$index = $table->getIndex($indexName);
|
||||
$this->assertTrue(in_array($name, $index->getColumns()));
|
||||
}
|
||||
}
|
||||
$this->assertEquals(array_get($definition, 'required', false), $table->getColumn($name)->getNotnull());
|
||||
}
|
||||
|
||||
$migration->down();
|
||||
$this->assertFalse(Schema::hasTable($this->table));
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
File::move($this->versionFile . '.bak', $this->versionFile);
|
||||
File::deleteDirectory($this->versionFolder);
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
}
|
||||
126
modules/system/tests/console/WinterEnvTest.php
Normal file
126
modules/system/tests/console/WinterEnvTest.php
Normal file
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Console;
|
||||
|
||||
use System\Tests\Bootstrap\TestCase;
|
||||
use Winter\Storm\Foundation\Bootstrap\LoadConfiguration;
|
||||
|
||||
class WinterEnvTest extends TestCase
|
||||
{
|
||||
/** @var bool If the config fixtures have been copied */
|
||||
public static $fixturesCopied = false;
|
||||
|
||||
/** @var string Stores the original config path from the app container */
|
||||
public static $origConfigPath;
|
||||
|
||||
/** @var string Stores the original environment path from the app container */
|
||||
public static $origEnvPath;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->setUpConfigFixtures();
|
||||
}
|
||||
|
||||
public function testCommand()
|
||||
{
|
||||
$this->artisan('winter:env')
|
||||
->assertExitCode(0);
|
||||
|
||||
// Check environment file
|
||||
$envFile = file_get_contents($this->app->environmentFilePath());
|
||||
|
||||
$this->assertStringContainsString('APP_DEBUG=true', $envFile);
|
||||
$this->assertStringContainsString('APP_URL="https://env-test.localhost"', $envFile);
|
||||
$this->assertStringContainsString('DB_CONNECTION="mysql"', $envFile);
|
||||
$this->assertStringContainsString('DB_DATABASE="data#base"', $envFile);
|
||||
$this->assertStringContainsString('DB_USERNAME="teal\'c"', $envFile);
|
||||
$this->assertStringContainsString('DB_PASSWORD="test\\"quotes\'test"', $envFile);
|
||||
$this->assertStringContainsString('DB_PORT=3306', $envFile);
|
||||
|
||||
// Check app.php config file
|
||||
$appConfigFile = file_get_contents(storage_path('temp/tests/config/app.php'));
|
||||
|
||||
$this->assertStringContainsString('\'debug\' => env(\'APP_DEBUG\', true),', $appConfigFile);
|
||||
$this->assertStringContainsString('\'url\' => env(\'APP_URL\', \'https://env-test.localhost\'),', $appConfigFile);
|
||||
|
||||
// Check database.php config file
|
||||
$appConfigFile = file_get_contents(storage_path('temp/tests/config/database.php'));
|
||||
|
||||
$this->assertStringContainsString('\'default\' => env(\'DB_CONNECTION\', \'mysql\')', $appConfigFile);
|
||||
$this->assertStringContainsString('\'port\' => env(\'DB_PORT\', 3306),', $appConfigFile);
|
||||
// Both the following configurations had values in the original config, they should be stripped out once
|
||||
// the .env file is generated.
|
||||
$this->assertStringContainsString('\'username\' => env(\'DB_USERNAME\', \'\'),', $appConfigFile);
|
||||
$this->assertStringContainsString('\'password\' => env(\'DB_PASSWORD\', \'\'),', $appConfigFile);
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
$this->tearDownConfigFixtures();
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
protected function setUpConfigFixtures()
|
||||
{
|
||||
// Mock config path and copy fixtures
|
||||
if (!is_dir(storage_path('temp/tests/config'))) {
|
||||
mkdir(storage_path('temp/tests/config'), 0777, true);
|
||||
}
|
||||
if (!is_dir(storage_path('temp/tests/env'))) {
|
||||
mkdir(storage_path('temp/tests/env'), 0777, true);
|
||||
}
|
||||
|
||||
foreach (glob(base_path('modules/system/tests/fixtures/config/*.php')) as $file) {
|
||||
$path = pathinfo($file);
|
||||
copy($file, storage_path('temp/tests/config/' . $path['basename']));
|
||||
}
|
||||
|
||||
static::$fixturesCopied = true;
|
||||
|
||||
// Store original config path
|
||||
static::$origConfigPath = $this->app->make('path.config');
|
||||
static::$origEnvPath = $this->app->environmentPath();
|
||||
|
||||
$this->app->instance('path.config', storage_path('temp/tests/config'));
|
||||
$this->app->useEnvironmentPath(storage_path('temp/tests/env'));
|
||||
|
||||
// Re-load configuration
|
||||
$configBootstrap = new LoadConfiguration;
|
||||
$configBootstrap->bootstrap($this->app);
|
||||
}
|
||||
|
||||
protected function tearDownConfigFixtures()
|
||||
{
|
||||
// Remove copied config fixtures
|
||||
if (static::$fixturesCopied) {
|
||||
foreach (glob(storage_path('temp/tests/config/*.php')) as $file) {
|
||||
unlink($file);
|
||||
}
|
||||
rmdir(storage_path('temp/tests/config'));
|
||||
unlink(storage_path('temp/tests/env/.env'));
|
||||
rmdir(storage_path('temp/tests/env'));
|
||||
rmdir(storage_path('temp/tests'));
|
||||
|
||||
static::$fixturesCopied = false;
|
||||
}
|
||||
|
||||
// Restore config path
|
||||
if (self::$origConfigPath) {
|
||||
$this->app->instance('path.config', static::$origConfigPath);
|
||||
static::$origConfigPath = null;
|
||||
}
|
||||
|
||||
// Restore environment path
|
||||
if (self::$origEnvPath) {
|
||||
$this->app->useEnvironmentPath(static::$origEnvPath);
|
||||
static::$origEnvPath = null;
|
||||
}
|
||||
|
||||
// Re-load configuration
|
||||
$configBootstrap = new LoadConfiguration;
|
||||
$configBootstrap->bootstrap($this->app);
|
||||
}
|
||||
}
|
||||
98
modules/system/tests/console/WinterUtilTest.php
Normal file
98
modules/system/tests/console/WinterUtilTest.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Console;
|
||||
|
||||
use System\Tests\Bootstrap\TestCase;
|
||||
|
||||
class WinterUtilTest extends TestCase
|
||||
{
|
||||
protected string $defaultClient;
|
||||
protected string $langClient;
|
||||
protected string $langCountryClient;
|
||||
protected array $createdDirs = [];
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->defaultClient = base_path('modules/system/lang/en/client.php');
|
||||
$this->langClient = base_path('lang/en/system/client.php');
|
||||
$this->langCountryClient = base_path('lang/en-gb/system/client.php');
|
||||
|
||||
// Backup original files
|
||||
if (file_exists($this->defaultClient)) {
|
||||
rename($this->defaultClient, $this->defaultClient . '.backup');
|
||||
}
|
||||
if (file_exists($this->langClient)) {
|
||||
rename($this->langClient, $this->langClient . '.backup');
|
||||
}
|
||||
if (file_exists($this->langCountryClient)) {
|
||||
rename($this->langCountryClient, $this->langCountryClient . '.backup');
|
||||
}
|
||||
}
|
||||
|
||||
public function testCompileLang()
|
||||
{
|
||||
file_put_contents($this->defaultClient, '<?php return [\'winter\' => \'is coming\'];');
|
||||
|
||||
// execute compile
|
||||
$this->artisan('winter:util compile lang')->execute();
|
||||
|
||||
// validate default lang handling
|
||||
$lang = file_get_contents(base_path('modules/system/assets/js/lang/lang.en.js'));
|
||||
$this->assertStringContainsString('winter', $lang);
|
||||
$this->assertStringContainsString('is coming', $lang);
|
||||
|
||||
// simulate override
|
||||
$this->createdDirs = [];
|
||||
|
||||
foreach (['lang/en/system', 'lang/en-gb/system'] as $slug) {
|
||||
$path = rtrim(base_path(), '/');
|
||||
foreach (explode('/', $slug) as $dir) {
|
||||
$path = $path . '/' . $dir;
|
||||
if (!is_dir($path)) {
|
||||
mkdir($path, 0755);
|
||||
$this->createdDirs[] = $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file_put_contents($this->langClient, '<?php return [\'winter\' => \'is epic\'];');
|
||||
|
||||
file_put_contents($this->langCountryClient, '<?php return [\'whats_epic\' => \'winter\'];');
|
||||
|
||||
// execute compile
|
||||
$this->artisan('winter:util compile lang')->execute();
|
||||
|
||||
// validate override handling
|
||||
$lang = file_get_contents(base_path('modules/system/assets/js/lang/lang.en.js'));
|
||||
$this->assertStringContainsString('winter', $lang);
|
||||
$this->assertStringContainsString('is epic', $lang);
|
||||
|
||||
// check that lang subset has included parent overrides
|
||||
$lang = file_get_contents(base_path('modules/system/assets/js/lang/lang.en-gb.js'));
|
||||
$this->assertStringContainsString('winter', $lang);
|
||||
$this->assertStringContainsString('is epic', $lang);
|
||||
$this->assertStringContainsString('whats_epic', $lang);
|
||||
$this->assertStringContainsString('winter', $lang);
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
unlink($this->defaultClient);
|
||||
rename($this->defaultClient . '.backup', $this->defaultClient);
|
||||
|
||||
foreach ([$this->langClient, $this->langCountryClient] as $client) {
|
||||
unlink($client);
|
||||
if (file_exists($client . '.backup')) {
|
||||
rename($client . '.backup', $client);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (array_reverse($this->createdDirs) as $dir) {
|
||||
rmdir($dir);
|
||||
}
|
||||
|
||||
$this->artisan('winter:util compile lang')->execute();
|
||||
}
|
||||
}
|
||||
19
modules/system/tests/console/asset/NpmTestTrait.php
Normal file
19
modules/system/tests/console/asset/NpmTestTrait.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Console\Asset;
|
||||
|
||||
trait NpmTestTrait
|
||||
{
|
||||
protected string $jsonPath;
|
||||
protected string $backupPath;
|
||||
|
||||
/**
|
||||
* Helper to run test logic and handle restoring package.json file after
|
||||
*/
|
||||
protected function withPackageJsonRestore(callable $callback): void
|
||||
{
|
||||
copy($this->jsonPath, $this->backupPath);
|
||||
$callback();
|
||||
rename($this->backupPath, $this->jsonPath);
|
||||
}
|
||||
}
|
||||
100
modules/system/tests/console/asset/mix/MixCompileTest.php
Normal file
100
modules/system/tests/console/asset/mix/MixCompileTest.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Console\Asset\Mix;
|
||||
|
||||
use System\Tests\Bootstrap\TestCase;
|
||||
use Winter\Storm\Support\Facades\File;
|
||||
|
||||
class MixCompileTest extends TestCase
|
||||
{
|
||||
protected string $command = 'mix:compile';
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
if (!File::exists(base_path('node_modules'))) {
|
||||
$this->markTestSkipped('This test requires node_modules to be installed');
|
||||
}
|
||||
|
||||
if (!File::exists(base_path('node_modules/.bin/mix'))) {
|
||||
$this->markTestSkipped('This test requires the mix package to be installed');
|
||||
}
|
||||
}
|
||||
|
||||
public function testCompileMultiple()
|
||||
{
|
||||
$this->artisan($this->command, [
|
||||
'--manifest' => 'modules/system/tests/fixtures/npm/package-ac.json',
|
||||
'--silent' => true
|
||||
])->assertExitCode(0);
|
||||
|
||||
$this->assertFileExists(base_path('modules/system/tests/fixtures/plugins/mix/testa/assets/dist/app.js'));
|
||||
$this->assertFileExists(base_path('modules/system/tests/fixtures/plugins/mix/testc/assets/dist/app.js'));
|
||||
}
|
||||
|
||||
public function testCompileMultipleWithErrors()
|
||||
{
|
||||
$this->artisan($this->command, [
|
||||
'--manifest' => 'modules/system/tests/fixtures/npm/package-abc.json',
|
||||
'--disable-tty' => true
|
||||
])
|
||||
->expectsOutputToContain('Error: Can\'t resolve \'some-missing-package\'')
|
||||
->assertExitCode(1);
|
||||
|
||||
$this->assertFileExists(base_path('modules/system/tests/fixtures/plugins/mix/testa/assets/dist/app.js'));
|
||||
$this->assertFileExists(base_path('modules/system/tests/fixtures/plugins/mix/testb/assets/dist/app.js'));
|
||||
$this->assertFileExists(base_path('modules/system/tests/fixtures/plugins/mix/testc/assets/dist/app.js'));
|
||||
}
|
||||
|
||||
public function testCompileTarget()
|
||||
{
|
||||
$this->artisan($this->command, [
|
||||
'--manifest' => 'modules/system/tests/fixtures/npm/package-abc.json',
|
||||
'--package' => 'mix.testa',
|
||||
'--silent' => true
|
||||
])->assertExitCode(0);
|
||||
|
||||
$this->assertFileExists(base_path('modules/system/tests/fixtures/plugins/mix/testa/assets/dist/app.js'));
|
||||
$this->assertFileNotExists(base_path('modules/system/tests/fixtures/plugins/mix/testb/assets/dist/app.js'));
|
||||
$this->assertFileNotExists(base_path('modules/system/tests/fixtures/plugins/mix/testc/assets/dist/app.js'));
|
||||
}
|
||||
|
||||
public function testCompileTargetWithError()
|
||||
{
|
||||
$this->artisan($this->command, [
|
||||
'--manifest' => 'modules/system/tests/fixtures/npm/package-abc.json',
|
||||
'--package' => 'mix.testb',
|
||||
'--disable-tty' => true
|
||||
])
|
||||
->expectsOutputToContain('Error: Can\'t resolve \'some-missing-package\'')
|
||||
->assertExitCode(1);
|
||||
|
||||
$this->assertFileNotExists(base_path('modules/system/tests/fixtures/plugins/mix/testa/assets/dist/app.js'));
|
||||
$this->assertFileNotExists(base_path('modules/system/tests/fixtures/plugins/mix/testc/assets/dist/app.js'));
|
||||
$this->assertFileExists(base_path('modules/system/tests/fixtures/plugins/mix/testb/assets/dist/app.js'));
|
||||
}
|
||||
|
||||
public function testCompileTargetStopOnError()
|
||||
{
|
||||
$this->artisan($this->command, [
|
||||
'--manifest' => 'modules/system/tests/fixtures/npm/package-abc.json',
|
||||
'--stop-on-error' => true,
|
||||
'--disable-tty' => true
|
||||
])
|
||||
->expectsOutputToContain('Error: Can\'t resolve \'some-missing-package\'')
|
||||
->assertExitCode(1);
|
||||
|
||||
$this->assertFileExists(base_path('modules/system/tests/fixtures/plugins/mix/testa/assets/dist/app.js'));
|
||||
$this->assertFileExists(base_path('modules/system/tests/fixtures/plugins/mix/testb/assets/dist/app.js'));
|
||||
$this->assertFileNotExists(base_path('modules/system/tests/fixtures/plugins/mix/testc/assets/dist/app.js'));
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
File::deleteDirectory('modules/system/tests/fixtures/plugins/mix/testa/assets/dist');
|
||||
File::deleteDirectory('modules/system/tests/fixtures/plugins/mix/testb/assets/dist');
|
||||
File::deleteDirectory('modules/system/tests/fixtures/plugins/mix/testc/assets/dist');
|
||||
parent::tearDown();
|
||||
}
|
||||
}
|
||||
234
modules/system/tests/console/asset/mix/MixCreateTest.php
Normal file
234
modules/system/tests/console/asset/mix/MixCreateTest.php
Normal file
@@ -0,0 +1,234 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Console\Asset\Mix;
|
||||
|
||||
use System\Classes\PluginManager;
|
||||
use System\Tests\Bootstrap\TestCase;
|
||||
use Winter\Storm\Support\Facades\File;
|
||||
|
||||
class MixCreateTest extends TestCase
|
||||
{
|
||||
protected string $testPlugin = 'Winter.Sample';
|
||||
|
||||
public function testConfigWritten(): void
|
||||
{
|
||||
$path = PluginManager::instance()->findByIdentifier($this->testPlugin)->getPluginPath();
|
||||
$configPath = $path . '/winter.mix.js';
|
||||
|
||||
// Check file does not exist
|
||||
$this->assertFileNotExists($configPath);
|
||||
|
||||
// Run the config command to generate the vite config
|
||||
$this->artisan('mix:create', [
|
||||
'packageName' => $this->testPlugin,
|
||||
'--no-stubs' => true,
|
||||
])
|
||||
->doesntExpectOutput('winter.mix.js already exists, overwrite?')
|
||||
->assertExitCode(0);
|
||||
|
||||
// Validate the manifest was written
|
||||
$this->assertFileExists($configPath);
|
||||
|
||||
// Get the predicted contents
|
||||
$fixture = str_replace(
|
||||
'{{packageName}}',
|
||||
'winter-sample',
|
||||
File::get(base_path('modules/system/console/asset/fixtures/config/mix/winter.mix.js.fixture')),
|
||||
);
|
||||
|
||||
// Check the file written is what was expected
|
||||
$this->assertEquals($fixture, File::get($configPath));
|
||||
|
||||
// Overwrite the file content
|
||||
File::put($configPath, 'testing');
|
||||
|
||||
// Check that refusing to overwrite does not replace file contents
|
||||
$this->artisan('mix:create', [
|
||||
'packageName' => $this->testPlugin,
|
||||
'--no-stubs' => true,
|
||||
])
|
||||
->expectsQuestion('winter.mix.js already exists, overwrite?', false)
|
||||
->assertExitCode(0);
|
||||
|
||||
// Check file contents was not overwritten
|
||||
$this->assertNotEquals($fixture, File::get($configPath));
|
||||
|
||||
// Run command confirming to overwrite file contents works
|
||||
$this->artisan('mix:create', [
|
||||
'packageName' => $this->testPlugin,
|
||||
'--no-stubs' => true,
|
||||
])
|
||||
->expectsQuestion('winter.mix.js already exists, overwrite?', true)
|
||||
->assertExitCode(0);
|
||||
|
||||
// Check file contents was overwritten
|
||||
$this->assertEquals($fixture, File::get($configPath));
|
||||
}
|
||||
|
||||
public function testConfigTailwind(): void
|
||||
{
|
||||
$path = PluginManager::instance()->findByIdentifier($this->testPlugin)->getPluginPath();
|
||||
$configPath = $path . '/winter.mix.js';
|
||||
$packageJson = $path . '/package.json';
|
||||
|
||||
// Check file does not exist
|
||||
$this->assertFileNotExists($configPath);
|
||||
|
||||
// Run the config command to generate the vite config
|
||||
$this->artisan('mix:create', [
|
||||
'packageName' => $this->testPlugin,
|
||||
'--tailwind' => true,
|
||||
'--no-stubs' => true,
|
||||
])
|
||||
->assertExitCode(0);
|
||||
|
||||
// Check files are created correctly
|
||||
$this->assertFileExists($configPath);
|
||||
$this->assertFileExists($path . '/tailwind.config.js');
|
||||
$this->assertFileExists($path . '/postcss.config.mjs');
|
||||
|
||||
// Get the contents of the package.json
|
||||
$json = json_decode(File::get($packageJson));
|
||||
|
||||
// Check tailwindcss is required
|
||||
$this->assertTrue(isset($json->devDependencies->tailwindcss));
|
||||
}
|
||||
|
||||
public function testConfigReact(): void
|
||||
{
|
||||
$path = PluginManager::instance()->findByIdentifier($this->testPlugin)->getPluginPath();
|
||||
$configPath = $path . '/winter.mix.js';
|
||||
$packageJson = $path . '/package.json';
|
||||
|
||||
// Check file does not exist
|
||||
$this->assertFileNotExists($configPath);
|
||||
|
||||
// Run the config command to generate the vite config with react
|
||||
$this->artisan('mix:create', [
|
||||
'packageName' => $this->testPlugin,
|
||||
'--react' => true,
|
||||
'--no-stubs' => true,
|
||||
])
|
||||
->assertExitCode(0);
|
||||
|
||||
// Check files are created correctly
|
||||
$this->assertFileExists($configPath);
|
||||
$this->assertFileExists($packageJson);
|
||||
|
||||
// Get the contents of the package.json
|
||||
$json = json_decode(File::get($packageJson));
|
||||
|
||||
// Check react is required
|
||||
$this->assertTrue(isset($json->devDependencies->react));
|
||||
}
|
||||
|
||||
public function testConfigTailwindReact(): void
|
||||
{
|
||||
$path = PluginManager::instance()->findByIdentifier($this->testPlugin)->getPluginPath();
|
||||
$configPath = $path . '/winter.mix.js';
|
||||
$packageJson = $path . '/package.json';
|
||||
|
||||
// Check file does not exist
|
||||
$this->assertFileNotExists($configPath);
|
||||
|
||||
// Run the config command to generate the vite config with react
|
||||
$this->artisan('mix:create', [
|
||||
'packageName' => $this->testPlugin,
|
||||
'--tailwind' => true,
|
||||
'--react' => true,
|
||||
'--no-stubs' => true,
|
||||
])
|
||||
->assertExitCode(0);
|
||||
|
||||
// Check files are created correctly
|
||||
$this->assertFileExists($configPath);
|
||||
$this->assertFileExists($packageJson);
|
||||
$this->assertFileExists($path . '/tailwind.config.js');
|
||||
$this->assertFileExists($path . '/postcss.config.mjs');
|
||||
|
||||
// Get the contents of the package.json
|
||||
$json = json_decode(File::get($packageJson));
|
||||
|
||||
// Check tailwind & react are required
|
||||
$this->assertTrue(isset($json->devDependencies->tailwindcss));
|
||||
$this->assertTrue(isset($json->devDependencies->react));
|
||||
}
|
||||
|
||||
public function testConfigVue(): void
|
||||
{
|
||||
$path = PluginManager::instance()->findByIdentifier($this->testPlugin)->getPluginPath();
|
||||
$configPath = $path . '/winter.mix.js';
|
||||
$packageJson = $path . '/package.json';
|
||||
|
||||
// Check file does not exist
|
||||
$this->assertFileNotExists($configPath);
|
||||
|
||||
// Run the config command to generate the vite config with vue
|
||||
$this->artisan('mix:create', [
|
||||
'packageName' => $this->testPlugin,
|
||||
'--vue' => true,
|
||||
'--no-stubs' => true,
|
||||
])
|
||||
->assertExitCode(0);
|
||||
|
||||
// Check files are created correctly
|
||||
$this->assertFileExists($configPath);
|
||||
$this->assertFileExists($packageJson);
|
||||
|
||||
// Get the contents of the package.json
|
||||
$json = json_decode(File::get($packageJson));
|
||||
|
||||
// Check vue is required
|
||||
$this->assertTrue(isset($json->devDependencies->vue));
|
||||
}
|
||||
|
||||
public function testConfigTailwindVue(): void
|
||||
{
|
||||
$path = PluginManager::instance()->findByIdentifier($this->testPlugin)->getPluginPath();
|
||||
$configPath = $path . '/winter.mix.js';
|
||||
$packageJson = $path . '/package.json';
|
||||
|
||||
// Check file does not exist
|
||||
$this->assertFileNotExists($configPath);
|
||||
|
||||
// Run the config command to generate the vite config with vue
|
||||
$this->artisan('mix:create', [
|
||||
'packageName' => $this->testPlugin,
|
||||
'--tailwind' => true,
|
||||
'--vue' => true,
|
||||
'--no-stubs' => true,
|
||||
])
|
||||
->assertExitCode(0);
|
||||
|
||||
// Check files are created correctly
|
||||
$this->assertFileExists($configPath);
|
||||
$this->assertFileExists($packageJson);
|
||||
$this->assertFileExists($path . '/tailwind.config.js');
|
||||
$this->assertFileExists($path . '/postcss.config.mjs');
|
||||
|
||||
// Get the contents of the package.json
|
||||
$json = json_decode(File::get($packageJson));
|
||||
|
||||
// Check tailwind & vue are required
|
||||
$this->assertTrue(isset($json->devDependencies->tailwindcss));
|
||||
$this->assertTrue(isset($json->devDependencies->vue));
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
$path = PluginManager::instance()->findByIdentifier($this->testPlugin)->getPluginPath();
|
||||
|
||||
$files = [
|
||||
$path . '/winter.mix.js',
|
||||
$path . '/package.json',
|
||||
$path . '/tailwind.config.js',
|
||||
$path . '/postcss.config.mjs',
|
||||
];
|
||||
|
||||
foreach ($files as $file) {
|
||||
if (File::exists($file)) {
|
||||
File::delete($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
213
modules/system/tests/console/asset/mix/MixInstallTest.php
Normal file
213
modules/system/tests/console/asset/mix/MixInstallTest.php
Normal file
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Console\Asset\Mix;
|
||||
|
||||
use System\Classes\Asset\PackageManager;
|
||||
use System\Tests\Bootstrap\TestCase;
|
||||
use Winter\Storm\Exception\SystemException;
|
||||
use Winter\Storm\Support\Facades\File;
|
||||
|
||||
class MixInstallTest extends TestCase
|
||||
{
|
||||
protected string $fixturePath;
|
||||
protected string $jsonPath;
|
||||
protected string $lockPath;
|
||||
protected string $backupPath;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
if (!File::exists(base_path('node_modules'))) {
|
||||
$this->markTestSkipped('This test requires node_modules to be installed');
|
||||
}
|
||||
|
||||
// Define some helpful paths
|
||||
$this->fixturePath = base_path('modules/system/tests');
|
||||
$this->jsonPath = $this->fixturePath . '/package.json';
|
||||
$this->lockPath = $this->fixturePath . '/package-lock.json';
|
||||
$this->backupPath = $this->fixturePath . '/package-testing.json';
|
||||
|
||||
// Add our testing theme because it won't be auto discovered
|
||||
PackageManager::instance()->registerPackage(
|
||||
'theme-assettest',
|
||||
base_path('modules/system/tests/fixtures/themes/assettest/winter.mix.js'),
|
||||
'mix'
|
||||
);
|
||||
PackageManager::instance()->registerPackage(
|
||||
'theme-npmtest',
|
||||
base_path('modules/system/tests/fixtures/themes/npmtest/winter.mix.js'),
|
||||
'mix'
|
||||
);
|
||||
}
|
||||
|
||||
public function testMixInstallMissingPackageJson(): void
|
||||
{
|
||||
$this->artisan('mix:install', [
|
||||
'assetPackage' => ['theme-assettest'],
|
||||
'--package-json' => '/some/file',
|
||||
'--no-install' => true
|
||||
])
|
||||
->expectsOutputToContain('The supplied --package-json path does not exist.')
|
||||
->assertExitCode(1);
|
||||
}
|
||||
|
||||
public function testMixInstallSinglePackage(): void
|
||||
{
|
||||
$this->withPackageJsonRestore(function () {
|
||||
$this->artisan('mix:install', [
|
||||
'assetPackage' => ['theme-assettest'],
|
||||
'--package-json' => $this->jsonPath,
|
||||
'--no-install' => true
|
||||
])
|
||||
->expectsQuestion('laravel-mix was not found as a dependency in package.json, would you like to add it?', true)
|
||||
->expectsOutput('Adding theme-assettest (modules/system/tests/fixtures/themes/assettest) to the workspaces.packages property in package.json')
|
||||
->assertExitCode(0);
|
||||
|
||||
$this->assertFileExists($this->jsonPath);
|
||||
$packageJson = json_decode(File::get($this->jsonPath), JSON_OBJECT_AS_ARRAY);
|
||||
$this->assertArrayHasKey('devDependencies', $packageJson);
|
||||
$this->assertArrayHasKey('laravel-mix', $packageJson['devDependencies']);
|
||||
|
||||
$this->assertArrayHasKey('workspaces', $packageJson);
|
||||
$this->assertArrayHasKey('packages', $packageJson['workspaces']);
|
||||
$this->assertContains('modules/system/tests/fixtures/themes/assettest', $packageJson['workspaces']['packages']);
|
||||
});
|
||||
}
|
||||
|
||||
public function testMixInstallMultiplePackages(): void
|
||||
{
|
||||
$this->withPackageJsonRestore(function () {
|
||||
$this->artisan('mix:install', [
|
||||
'assetPackage' => ['theme-assettest', 'theme-npmtest'],
|
||||
'--package-json' => $this->jsonPath,
|
||||
'--no-install' => true
|
||||
])
|
||||
->expectsQuestion('laravel-mix was not found as a dependency in package.json, would you like to add it?', true)
|
||||
->expectsOutput('Adding theme-assettest (modules/system/tests/fixtures/themes/assettest) to the workspaces.packages property in package.json')
|
||||
->expectsOutput('Adding theme-npmtest (modules/system/tests/fixtures/themes/npmtest) to the workspaces.packages property in package.json')
|
||||
->assertExitCode(0);
|
||||
|
||||
$this->assertFileExists($this->jsonPath);
|
||||
$packageJson = json_decode(File::get($this->jsonPath), JSON_OBJECT_AS_ARRAY);
|
||||
$this->assertArrayHasKey('devDependencies', $packageJson);
|
||||
$this->assertArrayHasKey('laravel-mix', $packageJson['devDependencies']);
|
||||
|
||||
$this->assertArrayHasKey('workspaces', $packageJson);
|
||||
$this->assertArrayHasKey('packages', $packageJson['workspaces']);
|
||||
$this->assertContains('modules/system/tests/fixtures/themes/assettest', $packageJson['workspaces']['packages']);
|
||||
$this->assertContains('modules/system/tests/fixtures/themes/npmtest', $packageJson['workspaces']['packages']);
|
||||
});
|
||||
}
|
||||
|
||||
public function testMixInstallMissingPackage(): void
|
||||
{
|
||||
// We should receive an exception for a missing package
|
||||
$this->withPackageJsonRestore(function () {
|
||||
$this->expectException(SystemException::class);
|
||||
|
||||
$this->artisan('mix:install', [
|
||||
'assetPackage' => ['theme-assettest2'],
|
||||
'--package-json' => $this->jsonPath,
|
||||
'--no-install' => true
|
||||
])
|
||||
->assertExitCode(1);
|
||||
});
|
||||
}
|
||||
|
||||
public function testMixInstallRelativePath(): void
|
||||
{
|
||||
$this->withPackageJsonRestore(function () {
|
||||
$this->artisan('mix:install', [
|
||||
'assetPackage' => ['theme-assettest'],
|
||||
'--package-json' => 'modules/system/tests/package.json',
|
||||
'--no-install' => true
|
||||
])
|
||||
->expectsQuestion('laravel-mix was not found as a dependency in package.json, would you like to add it?', true)
|
||||
->expectsOutput('Adding theme-assettest (modules/system/tests/fixtures/themes/assettest) to the workspaces.packages property in package.json')
|
||||
->assertExitCode(0);
|
||||
});
|
||||
}
|
||||
|
||||
public function testMixInstallIgnoredPackage(): void
|
||||
{
|
||||
$this->withPackageJsonRestore(function () {
|
||||
$packageJson = json_decode(File::get($this->jsonPath), JSON_OBJECT_AS_ARRAY);
|
||||
$packageJson['workspaces'] = [
|
||||
'ignoredPackages' => [
|
||||
'modules/system/tests/fixtures/themes/assettest'
|
||||
]
|
||||
];
|
||||
File::put($this->jsonPath, json_encode($packageJson, JSON_PRETTY_PRINT));
|
||||
|
||||
$this->artisan('mix:install', [
|
||||
'assetPackage' => ['theme-assettest'],
|
||||
'--package-json' => $this->jsonPath,
|
||||
'--no-install' => true
|
||||
])
|
||||
->expectsQuestion('laravel-mix was not found as a dependency in package.json, would you like to add it?', false)
|
||||
->expectsOutput('The requested package theme-assettest (modules/system/tests/fixtures/themes/assettest) is ignored, remove it from package.json to continue.')
|
||||
->assertExitCode(0);
|
||||
|
||||
$packageJson = json_decode(File::get($this->jsonPath), JSON_OBJECT_AS_ARRAY);
|
||||
$this->assertArrayHasKey('workspaces', $packageJson);
|
||||
$this->assertArrayNotHasKey('packages', $packageJson['workspaces']);
|
||||
$this->assertArrayNotHasKey('dependencies', $packageJson);
|
||||
$this->assertArrayNotHasKey('devDependencies', $packageJson);
|
||||
});
|
||||
}
|
||||
|
||||
public function testMixInstallWithNpmInstall(): void
|
||||
{
|
||||
$this->withPackageJsonRestore(function () {
|
||||
$this->assertDirectoryDoesNotExist($this->fixturePath . '/node_modules');
|
||||
|
||||
$this->artisan('mix:install', [
|
||||
'assetPackage' => ['theme-assettest'],
|
||||
'--package-json' => $this->jsonPath,
|
||||
'--disable-tty' => true
|
||||
])
|
||||
->expectsQuestion('laravel-mix was not found as a dependency in package.json, would you like to add it?', true)
|
||||
->expectsOutput('Adding theme-assettest (modules/system/tests/fixtures/themes/assettest) to the workspaces.packages property in package.json')
|
||||
->expectsOutputToContain('packages, and audited') // output from npm i
|
||||
->assertExitCode(0);
|
||||
|
||||
$this->assertFileExists($this->jsonPath);
|
||||
$packageJson = json_decode(File::get($this->jsonPath), JSON_OBJECT_AS_ARRAY);
|
||||
$this->assertArrayHasKey('devDependencies', $packageJson);
|
||||
$this->assertArrayHasKey('laravel-mix', $packageJson['devDependencies']);
|
||||
|
||||
$this->assertArrayHasKey('workspaces', $packageJson);
|
||||
$this->assertArrayHasKey('packages', $packageJson['workspaces']);
|
||||
$this->assertContains('modules/system/tests/fixtures/themes/assettest', $packageJson['workspaces']['packages']);
|
||||
|
||||
$this->assertFileExists($this->lockPath);
|
||||
|
||||
$this->assertDirectoryExists($this->fixturePath . '/node_modules');
|
||||
$this->assertDirectoryExists($this->fixturePath . '/node_modules/laravel-mix');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to run test logic and handle restoring package.json file after
|
||||
*/
|
||||
protected function withPackageJsonRestore(callable $callback): void
|
||||
{
|
||||
File::copy($this->backupPath, $this->jsonPath);
|
||||
$callback();
|
||||
File::delete($this->jsonPath);
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
if (File::isDirectory($this->fixturePath . '/node_modules')) {
|
||||
File::deleteDirectory($this->fixturePath . '/node_modules');
|
||||
}
|
||||
|
||||
if (File::exists($this->lockPath)) {
|
||||
File::delete($this->lockPath);
|
||||
}
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
}
|
||||
209
modules/system/tests/console/asset/npm/NpmInstallTest.php
Normal file
209
modules/system/tests/console/asset/npm/NpmInstallTest.php
Normal file
@@ -0,0 +1,209 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Console\Asset\Npm;
|
||||
|
||||
use System\Classes\Asset\PackageManager;
|
||||
use System\Tests\Bootstrap\TestCase;
|
||||
use System\Tests\Console\Asset\NpmTestTrait;
|
||||
use Winter\Storm\Support\Facades\File;
|
||||
|
||||
class NpmInstallTest extends TestCase
|
||||
{
|
||||
use NpmTestTrait;
|
||||
|
||||
protected string $themePath;
|
||||
protected string $jsonPath;
|
||||
protected string $lockPath;
|
||||
protected string $backupPath;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
if (!File::exists(base_path('node_modules'))) {
|
||||
$this->markTestSkipped('This test requires node_modules to be installed');
|
||||
}
|
||||
|
||||
// Define some helpful paths
|
||||
$this->themePath = base_path('modules/system/tests/fixtures/themes/npmtest');
|
||||
$this->jsonPath = $this->themePath . '/package.json';
|
||||
$this->lockPath = $this->themePath . '/package-lock.json';
|
||||
$this->backupPath = $this->themePath . '/package.backup.json';
|
||||
|
||||
// Add our testing theme because it won't be auto discovered
|
||||
PackageManager::instance()->registerPackage(
|
||||
'theme-npmtest',
|
||||
$this->themePath . '/vite.config.mjs',
|
||||
'vite'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the ability to install a single npm package via artisan
|
||||
*/
|
||||
public function testNpmInstallSingle(): void
|
||||
{
|
||||
// Validate the package Json does not have dependencies
|
||||
$packageJson = json_decode(File::get($this->jsonPath), JSON_OBJECT_AS_ARRAY);
|
||||
$this->assertArrayNotHasKey('dependencies', $packageJson);
|
||||
|
||||
// Validate node_modules not found
|
||||
$this->assertDirectoryDoesNotExist($this->themePath . '/node_modules');
|
||||
$this->assertFileNotExists($this->lockPath);
|
||||
|
||||
$this->withPackageJsonRestore(function () {
|
||||
// Run npm install for a single non-dev package
|
||||
$this->artisan('npm:install', [
|
||||
'package' => 'theme-npmtest',
|
||||
'npmArgs' => ['is-odd'],
|
||||
'--disable-tty' => true
|
||||
])
|
||||
->assertExitCode(0);
|
||||
|
||||
// Validate lock file was generated successfully
|
||||
$this->assertFileExists($this->lockPath);
|
||||
|
||||
// Validate the contents of package.json
|
||||
$packageJson = json_decode(File::get($this->jsonPath), JSON_OBJECT_AS_ARRAY);
|
||||
$this->assertArrayHasKey('dependencies', $packageJson);
|
||||
$this->assertArrayHasKey('is-odd', $packageJson['dependencies']);
|
||||
|
||||
// Validate that node_modules paths exist
|
||||
$this->assertDirectoryExists($this->themePath . '/node_modules');
|
||||
$this->assertDirectoryExists($this->themePath . '/node_modules/is-odd');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the ability to install multiple npm packages via artisan
|
||||
*/
|
||||
public function testNpmInstallMultiple(): void
|
||||
{
|
||||
// Validate the package Json does not have dependencies
|
||||
$packageJson = json_decode(File::get($this->jsonPath), JSON_OBJECT_AS_ARRAY);
|
||||
$this->assertArrayNotHasKey('dependencies', $packageJson);
|
||||
|
||||
// Validate node_modules not found
|
||||
$this->assertDirectoryDoesNotExist($this->themePath . '/node_modules');
|
||||
$this->assertFileNotExists($this->lockPath);
|
||||
|
||||
$this->withPackageJsonRestore(function () {
|
||||
// Run npm install for multiple non-dev packages
|
||||
$this->artisan('npm:install', [
|
||||
'package' => 'theme-npmtest',
|
||||
'npmArgs' => ['is-odd', 'is-even'],
|
||||
'--disable-tty' => true
|
||||
])
|
||||
->assertExitCode(0);
|
||||
|
||||
// Validate lock file was generated successfully
|
||||
$this->assertFileExists($this->lockPath);
|
||||
|
||||
// Validate the contents of package.json
|
||||
$packageJson = json_decode(File::get($this->jsonPath), JSON_OBJECT_AS_ARRAY);
|
||||
$this->assertArrayHasKey('dependencies', $packageJson);
|
||||
$this->assertArrayHasKey('is-odd', $packageJson['dependencies']);
|
||||
$this->assertArrayHasKey('is-even', $packageJson['dependencies']);
|
||||
|
||||
// Validate that node_modules paths exist
|
||||
$this->assertDirectoryExists($this->themePath . '/node_modules');
|
||||
$this->assertDirectoryExists($this->themePath . '/node_modules/is-odd');
|
||||
$this->assertDirectoryExists($this->themePath . '/node_modules/is-even');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test the ability to install a single dev npm package via artisan
|
||||
*/
|
||||
public function testNpmInstallSingleDev(): void
|
||||
{
|
||||
// Validate the package Json does not have dependencies
|
||||
$packageJson = json_decode(File::get($this->jsonPath), JSON_OBJECT_AS_ARRAY);
|
||||
$this->assertArrayNotHasKey('devDependencies', $packageJson);
|
||||
|
||||
// Validate node_modules not found
|
||||
$this->assertDirectoryDoesNotExist($this->themePath . '/node_modules');
|
||||
$this->assertFileNotExists($this->lockPath);
|
||||
|
||||
$this->withPackageJsonRestore(function () {
|
||||
// Run npm install for a single dev package
|
||||
$this->artisan('npm:install', [
|
||||
'package' => 'theme-npmtest',
|
||||
'npmArgs' => ['is-odd'],
|
||||
'--dev' => true,
|
||||
'--disable-tty' => true
|
||||
])
|
||||
->assertExitCode(0);
|
||||
|
||||
// Validate lock file was generated successfully
|
||||
$this->assertFileExists($this->lockPath);
|
||||
|
||||
// Validate the contents of package.json
|
||||
$packageJson = json_decode(File::get($this->jsonPath), JSON_OBJECT_AS_ARRAY);
|
||||
$this->assertArrayHasKey('devDependencies', $packageJson);
|
||||
$this->assertArrayHasKey('is-odd', $packageJson['devDependencies']);
|
||||
|
||||
// Validate that node_modules paths exist
|
||||
$this->assertDirectoryExists($this->themePath . '/node_modules');
|
||||
$this->assertDirectoryExists($this->themePath . '/node_modules/is-odd');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the ability to install multiple dev npm packages via artisan
|
||||
*/
|
||||
public function testNpmInstallMultipleDev(): void
|
||||
{
|
||||
// Validate the package Json does not have dependencies
|
||||
$packageJson = json_decode(File::get($this->jsonPath), JSON_OBJECT_AS_ARRAY);
|
||||
$this->assertArrayNotHasKey('devDependencies', $packageJson);
|
||||
|
||||
// Validate node_modules not found
|
||||
$this->assertDirectoryDoesNotExist($this->themePath . '/node_modules');
|
||||
$this->assertFileNotExists($this->lockPath);
|
||||
|
||||
$this->withPackageJsonRestore(function () {
|
||||
// Run npm install for multiple dev packages
|
||||
$this->artisan('npm:install', [
|
||||
'package' => 'theme-npmtest',
|
||||
'npmArgs' => ['is-odd', 'is-even'],
|
||||
'--dev' => true,
|
||||
'--disable-tty' => true
|
||||
])
|
||||
->assertExitCode(0);
|
||||
|
||||
// Validate lock file was generated successfully
|
||||
$this->assertFileExists($this->lockPath);
|
||||
|
||||
// Validate the contents of package.json
|
||||
$packageJson = json_decode(File::get($this->jsonPath), JSON_OBJECT_AS_ARRAY);
|
||||
$this->assertArrayHasKey('devDependencies', $packageJson);
|
||||
$this->assertArrayHasKey('is-odd', $packageJson['devDependencies']);
|
||||
$this->assertArrayHasKey('is-even', $packageJson['devDependencies']);
|
||||
|
||||
// Validate that node_modules paths exist
|
||||
$this->assertDirectoryExists($this->themePath . '/node_modules');
|
||||
$this->assertDirectoryExists($this->themePath . '/node_modules/is-odd');
|
||||
$this->assertDirectoryExists($this->themePath . '/node_modules/is-even');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup the test theme
|
||||
*/
|
||||
public function tearDown(): void
|
||||
{
|
||||
if (File::isDirectory($this->themePath . '/node_modules')) {
|
||||
File::deleteDirectory($this->themePath . '/node_modules');
|
||||
}
|
||||
|
||||
foreach ([$this->backupPath, $this->lockPath] as $path) {
|
||||
if (File::exists($path)) {
|
||||
File::delete($path);
|
||||
}
|
||||
}
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
}
|
||||
55
modules/system/tests/console/asset/npm/NpmRunTest.php
Normal file
55
modules/system/tests/console/asset/npm/NpmRunTest.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Console\Asset\Npm;
|
||||
|
||||
use System\Classes\Asset\PackageManager;
|
||||
use System\Tests\Bootstrap\TestCase;
|
||||
use Winter\Storm\Support\Facades\File;
|
||||
|
||||
class NpmRunTest extends TestCase
|
||||
{
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
if (!File::exists(base_path('node_modules'))) {
|
||||
$this->markTestSkipped('This test requires node_modules to be installed');
|
||||
}
|
||||
|
||||
// Add our testing theme because it won't be auto discovered
|
||||
PackageManager::instance()->registerPackage(
|
||||
'theme-npmtest',
|
||||
base_path('modules/system/tests/fixtures/themes/npmtest/vite.config.mjs'),
|
||||
'vite'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the ability to run a npm script via artisan
|
||||
*/
|
||||
public function testNpmRunScript(): void
|
||||
{
|
||||
$this->artisan('npm:run', [
|
||||
'package' => 'theme-npmtest',
|
||||
'script' => 'testScript',
|
||||
'--disable-tty' => true
|
||||
])
|
||||
->expectsOutputToContain('> echo "Winter says $((1+2))"')
|
||||
->expectsOutputToContain('Winter says 3')
|
||||
->assertExitCode(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the error handling of a missing script
|
||||
*/
|
||||
public function testNpmRunScriptFailed(): void
|
||||
{
|
||||
$this->artisan('npm:run', [
|
||||
'package' => 'theme-npmtest',
|
||||
'script' => 'testMissingScript',
|
||||
'--disable-tty' => true
|
||||
])
|
||||
->expectsOutputToContain('Script "testMissingScript" is not defined in package "theme-npmtest"')
|
||||
->assertExitCode(1);
|
||||
}
|
||||
}
|
||||
104
modules/system/tests/console/asset/npm/NpmUpdateTest.php
Normal file
104
modules/system/tests/console/asset/npm/NpmUpdateTest.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace System\tests\console\asset\npm;
|
||||
|
||||
use System\Classes\Asset\PackageManager;
|
||||
use System\Tests\Bootstrap\TestCase;
|
||||
use System\Tests\Console\Asset\NpmTestTrait;
|
||||
use Winter\Storm\Support\Facades\File;
|
||||
|
||||
class NpmUpdateTest extends TestCase
|
||||
{
|
||||
use NpmTestTrait;
|
||||
|
||||
protected string $themePath;
|
||||
protected string $jsonPath;
|
||||
protected string $lockPath;
|
||||
protected string $backupPath;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
if (!File::exists(base_path('node_modules'))) {
|
||||
$this->markTestSkipped('This test requires node_modules to be installed');
|
||||
}
|
||||
|
||||
// Define some helpful paths
|
||||
$this->themePath = base_path('modules/system/tests/fixtures/themes/npmtest');
|
||||
$this->jsonPath = $this->themePath . '/package.json';
|
||||
$this->lockPath = $this->themePath . '/package-lock.json';
|
||||
$this->backupPath = $this->themePath . '/package.backup.json';
|
||||
|
||||
// Add our testing theme because it won't be auto discovered
|
||||
PackageManager::instance()->registerPackage(
|
||||
'theme-npmtest',
|
||||
$this->themePath . '/vite.config.mjs',
|
||||
'vite'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the ability to install a single npm package via artisan
|
||||
*/
|
||||
public function testNpmUpdate(): void
|
||||
{
|
||||
// Validate the package Json does not have dependencies
|
||||
$packageJson = json_decode(File::get($this->jsonPath), JSON_OBJECT_AS_ARRAY);
|
||||
$this->assertArrayNotHasKey('dependencies', $packageJson);
|
||||
|
||||
// Validate node_modules not found
|
||||
$this->assertDirectoryDoesNotExist($this->themePath . '/node_modules');
|
||||
$this->assertFileNotExists($this->lockPath);
|
||||
|
||||
$this->withPackageJsonRestore(function () {
|
||||
// Update the contents of package.json to include a package at an old patch
|
||||
$packageJson = json_decode(File::get($this->jsonPath), JSON_OBJECT_AS_ARRAY);
|
||||
$packageJson['dependencies'] = [
|
||||
'is-odd' => '^3.0.0'
|
||||
];
|
||||
File::put($this->jsonPath, json_encode($packageJson, JSON_PRETTY_PRINT));
|
||||
|
||||
// Run npm update
|
||||
$this->artisan('npm:update', [
|
||||
'package' => 'theme-npmtest',
|
||||
'--save' => true,
|
||||
'--disable-tty' => true
|
||||
])
|
||||
->assertExitCode(0);
|
||||
|
||||
// Validate lock file was generated successfully
|
||||
$this->assertFileExists($this->lockPath);
|
||||
|
||||
// Get the new contents of package.json
|
||||
$packageJson = json_decode(File::get($this->jsonPath), JSON_OBJECT_AS_ARRAY);
|
||||
|
||||
// Validate that the package.json contents does not match the old patch value we added above
|
||||
$this->assertArrayHasKey('dependencies', $packageJson);
|
||||
$this->assertArrayHasKey('is-odd', $packageJson['dependencies']);
|
||||
$this->assertNotEquals('^3.0.0', $packageJson['dependencies']['is-odd']);
|
||||
|
||||
// Validate that node_modules paths exist
|
||||
$this->assertDirectoryExists($this->themePath . '/node_modules');
|
||||
$this->assertDirectoryExists($this->themePath . '/node_modules/is-odd');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup the test theme
|
||||
*/
|
||||
public function tearDown(): void
|
||||
{
|
||||
if (File::isDirectory($this->themePath . '/node_modules')) {
|
||||
File::deleteDirectory($this->themePath . '/node_modules');
|
||||
}
|
||||
|
||||
foreach ([$this->backupPath, $this->lockPath] as $path) {
|
||||
if (File::exists($path)) {
|
||||
File::delete($path);
|
||||
}
|
||||
}
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
}
|
||||
118
modules/system/tests/console/asset/vite/ViteCompileTest.php
Normal file
118
modules/system/tests/console/asset/vite/ViteCompileTest.php
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Console\Asset\Vite;
|
||||
|
||||
use System\Classes\Asset\PackageManager;
|
||||
use System\Tests\Bootstrap\TestCase;
|
||||
use Winter\Storm\Support\Facades\File;
|
||||
|
||||
class ViteCompileTest extends TestCase
|
||||
{
|
||||
protected string $themePath;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
if (!File::exists(base_path('node_modules'))) {
|
||||
$this->markTestSkipped('This test requires node_modules to be installed');
|
||||
}
|
||||
|
||||
if (!File::exists(base_path('node_modules/.bin/vite'))) {
|
||||
$this->markTestSkipped('This test requires the vite package to be installed');
|
||||
}
|
||||
|
||||
$this->themePath = base_path('modules/system/tests/fixtures/themes/assettest');
|
||||
|
||||
// Add our testing theme because it won't be auto discovered
|
||||
PackageManager::instance()->registerPackage(
|
||||
'theme-assettest',
|
||||
$this->themePath . '/vite.config.mjs',
|
||||
'vite'
|
||||
);
|
||||
}
|
||||
|
||||
public function testThemeCompile(): void
|
||||
{
|
||||
// Run the vite:compile command
|
||||
$this->artisan('vite:compile', [
|
||||
'theme-assettest',
|
||||
'--manifest' => 'modules/system/tests/fixtures/npm/package-vitetheme.json',
|
||||
'--silent' => true
|
||||
])->assertExitCode(0);
|
||||
|
||||
$manifestPath = $this->themePath . '/public/build/manifest.json';
|
||||
|
||||
// Validate the manifest was written
|
||||
$this->assertFileExists($manifestPath);
|
||||
|
||||
// Get the contents of the manifest
|
||||
$manifest = json_decode(File::get($manifestPath), JSON_OBJECT_AS_ARRAY);
|
||||
|
||||
// Validate the css was compiled correctly
|
||||
$this->assertArrayHasKey('assets/css/theme.css', $manifest);
|
||||
$this->assertFileExists($this->themePath . '/public/build/' . $manifest['assets/css/theme.css']['file']);
|
||||
$this->assertEquals(
|
||||
'h1{color:red}',
|
||||
trim(File::get($this->themePath . '/public/build/' . $manifest['assets/css/theme.css']['file']))
|
||||
);
|
||||
|
||||
// Validate the js was compiled correctly
|
||||
$this->assertArrayHasKey('assets/javascript/theme.js', $manifest);
|
||||
$this->assertFileExists($this->themePath . '/public/build/' . $manifest['assets/javascript/theme.js']['file']);
|
||||
$this->assertEquals(
|
||||
'window.alert("hello world");',
|
||||
trim(File::get($this->themePath . '/public/build/' . $manifest['assets/javascript/theme.js']['file']))
|
||||
);
|
||||
}
|
||||
|
||||
public function testThemeCompileFailed(): void
|
||||
{
|
||||
// Rename the css file so vite cannot find it
|
||||
File::move($this->themePath . '/assets/css/theme.css', $this->themePath . '/assets/css/theme.back');
|
||||
|
||||
// Run the vite:compile command
|
||||
$this->artisan('vite:compile', [
|
||||
'theme-assettest',
|
||||
'--manifest' => 'modules/system/tests/fixtures/npm/package-vitetheme.json',
|
||||
'--disable-tty' => true
|
||||
])
|
||||
->expectsOutputToContain('Could not resolve entry module "assets/css/theme.css".')
|
||||
->assertExitCode(1);
|
||||
|
||||
// Validate the manifest was not written
|
||||
$this->assertFileNotExists($this->themePath . '/public/build/manifest.json');
|
||||
|
||||
// Put the css file back
|
||||
File::move($this->themePath . '/assets/css/theme.back', $this->themePath . '/assets/css/theme.css');
|
||||
}
|
||||
|
||||
public function testThemeCompileWarning(): void
|
||||
{
|
||||
// Rename the css file so vite cannot find it
|
||||
$contents = File::get($this->themePath . '/assets/css/theme.css');
|
||||
|
||||
File::put($this->themePath . '/assets/css/theme.css', 'h1 {color:');
|
||||
|
||||
// Run the vite:compile command
|
||||
$this->artisan('vite:compile', [
|
||||
'theme-assettest',
|
||||
'--manifest' => 'modules/system/tests/fixtures/npm/package-vitetheme.json',
|
||||
'--disable-tty' => true
|
||||
])
|
||||
->expectsOutputToContain('[WARNING] Expected "}" to go with "{" [css-syntax-error]')
|
||||
->assertExitCode(0);
|
||||
|
||||
// Validate the manifest was not written
|
||||
$this->assertFileExists($this->themePath . '/public/build/manifest.json');
|
||||
|
||||
// Put the css file back
|
||||
File::put($this->themePath . '/assets/css/theme.css', $contents);
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
File::deleteDirectory('modules/system/tests/fixtures/themes/assettest/public');
|
||||
parent::tearDown();
|
||||
}
|
||||
}
|
||||
234
modules/system/tests/console/asset/vite/ViteCreateTest.php
Normal file
234
modules/system/tests/console/asset/vite/ViteCreateTest.php
Normal file
@@ -0,0 +1,234 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Console\Asset\Vite;
|
||||
|
||||
use System\Classes\PluginManager;
|
||||
use System\Tests\Bootstrap\TestCase;
|
||||
use Winter\Storm\Support\Facades\File;
|
||||
|
||||
class ViteCreateTest extends TestCase
|
||||
{
|
||||
protected string $testPlugin = 'Winter.Sample';
|
||||
|
||||
public function testConfigWritten(): void
|
||||
{
|
||||
$path = PluginManager::instance()->findByIdentifier($this->testPlugin)->getPluginPath();
|
||||
$configPath = $path . '/vite.config.mjs';
|
||||
|
||||
// Check file does not exist
|
||||
$this->assertFileNotExists($configPath);
|
||||
|
||||
// Run the config command to generate the vite config
|
||||
$this->artisan('vite:create', [
|
||||
'packageName' => $this->testPlugin,
|
||||
'--no-stubs' => true,
|
||||
])
|
||||
->doesntExpectOutput('vite.config.mjs already exists, overwrite?')
|
||||
->assertExitCode(0);
|
||||
|
||||
// Validate the manifest was written
|
||||
$this->assertFileExists($configPath);
|
||||
|
||||
// Get the predicted contents
|
||||
$fixture = str_replace(
|
||||
'{{packageName}}',
|
||||
'winter-sample',
|
||||
File::get(base_path('modules/system/console/asset/fixtures/config/vite/vite.config.mjs.fixture')),
|
||||
);
|
||||
|
||||
// Check the file written is what was expected
|
||||
$this->assertEquals($fixture, File::get($configPath));
|
||||
|
||||
// Overwrite the file content
|
||||
File::put($configPath, 'testing');
|
||||
|
||||
// Check that refusing to overwrite does not replace file contents
|
||||
$this->artisan('vite:create', [
|
||||
'packageName' => $this->testPlugin,
|
||||
'--no-stubs' => true,
|
||||
])
|
||||
->expectsQuestion('vite.config.mjs already exists, overwrite?', false)
|
||||
->assertExitCode(0);
|
||||
|
||||
// Check file contents was not overwritten
|
||||
$this->assertNotEquals($fixture, File::get($configPath));
|
||||
|
||||
// Run command confirming to overwrite file contents works
|
||||
$this->artisan('vite:create', [
|
||||
'packageName' => $this->testPlugin,
|
||||
'--no-stubs' => true,
|
||||
])
|
||||
->expectsQuestion('vite.config.mjs already exists, overwrite?', true)
|
||||
->assertExitCode(0);
|
||||
|
||||
// Check file contents was overwritten
|
||||
$this->assertEquals($fixture, File::get($configPath));
|
||||
}
|
||||
|
||||
public function testConfigTailwind(): void
|
||||
{
|
||||
$path = PluginManager::instance()->findByIdentifier($this->testPlugin)->getPluginPath();
|
||||
$configPath = $path . '/vite.config.mjs';
|
||||
$packageJson = $path . '/package.json';
|
||||
|
||||
// Check file does not exist
|
||||
$this->assertFileNotExists($configPath);
|
||||
|
||||
// Run the config command to generate the vite config
|
||||
$this->artisan('vite:create', [
|
||||
'packageName' => $this->testPlugin,
|
||||
'--tailwind' => true,
|
||||
'--no-stubs' => true,
|
||||
])
|
||||
->assertExitCode(0);
|
||||
|
||||
// Check files are created correctly
|
||||
$this->assertFileExists($configPath);
|
||||
$this->assertFileExists($path . '/tailwind.config.js');
|
||||
$this->assertFileExists($path . '/postcss.config.mjs');
|
||||
|
||||
// Get the contents of the package.json
|
||||
$json = json_decode(File::get($packageJson));
|
||||
|
||||
// Check tailwindcss is required
|
||||
$this->assertTrue(isset($json->devDependencies->tailwindcss));
|
||||
}
|
||||
|
||||
public function testConfigReact(): void
|
||||
{
|
||||
$path = PluginManager::instance()->findByIdentifier($this->testPlugin)->getPluginPath();
|
||||
$configPath = $path . '/vite.config.mjs';
|
||||
$packageJson = $path . '/package.json';
|
||||
|
||||
// Check file does not exist
|
||||
$this->assertFileNotExists($configPath);
|
||||
|
||||
// Run the config command to generate the vite config with react
|
||||
$this->artisan('vite:create', [
|
||||
'packageName' => $this->testPlugin,
|
||||
'--react' => true,
|
||||
'--no-stubs' => true,
|
||||
])
|
||||
->assertExitCode(0);
|
||||
|
||||
// Check files are created correctly
|
||||
$this->assertFileExists($configPath);
|
||||
$this->assertFileExists($packageJson);
|
||||
|
||||
// Get the contents of the package.json
|
||||
$json = json_decode(File::get($packageJson));
|
||||
|
||||
// Check react is required
|
||||
$this->assertTrue(isset($json->devDependencies->react));
|
||||
}
|
||||
|
||||
public function testConfigTailwindReact(): void
|
||||
{
|
||||
$path = PluginManager::instance()->findByIdentifier($this->testPlugin)->getPluginPath();
|
||||
$configPath = $path . '/vite.config.mjs';
|
||||
$packageJson = $path . '/package.json';
|
||||
|
||||
// Check file does not exist
|
||||
$this->assertFileNotExists($configPath);
|
||||
|
||||
// Run the config command to generate the vite config with react
|
||||
$this->artisan('vite:create', [
|
||||
'packageName' => $this->testPlugin,
|
||||
'--tailwind' => true,
|
||||
'--react' => true,
|
||||
'--no-stubs' => true,
|
||||
])
|
||||
->assertExitCode(0);
|
||||
|
||||
// Check files are created correctly
|
||||
$this->assertFileExists($configPath);
|
||||
$this->assertFileExists($packageJson);
|
||||
$this->assertFileExists($path . '/tailwind.config.js');
|
||||
$this->assertFileExists($path . '/postcss.config.mjs');
|
||||
|
||||
// Get the contents of the package.json
|
||||
$json = json_decode(File::get($packageJson));
|
||||
|
||||
// Check tailwind & react are required
|
||||
$this->assertTrue(isset($json->devDependencies->tailwindcss));
|
||||
$this->assertTrue(isset($json->devDependencies->react));
|
||||
}
|
||||
|
||||
public function testConfigVue(): void
|
||||
{
|
||||
$path = PluginManager::instance()->findByIdentifier($this->testPlugin)->getPluginPath();
|
||||
$configPath = $path . '/vite.config.mjs';
|
||||
$packageJson = $path . '/package.json';
|
||||
|
||||
// Check file does not exist
|
||||
$this->assertFileNotExists($configPath);
|
||||
|
||||
// Run the config command to generate the vite config with vue
|
||||
$this->artisan('vite:create', [
|
||||
'packageName' => $this->testPlugin,
|
||||
'--vue' => true,
|
||||
'--no-stubs' => true,
|
||||
])
|
||||
->assertExitCode(0);
|
||||
|
||||
// Check files are created correctly
|
||||
$this->assertFileExists($configPath);
|
||||
$this->assertFileExists($packageJson);
|
||||
|
||||
// Get the contents of the package.json
|
||||
$json = json_decode(File::get($packageJson));
|
||||
|
||||
// Check vue is required
|
||||
$this->assertTrue(isset($json->devDependencies->vue));
|
||||
}
|
||||
|
||||
public function testConfigTailwindVue(): void
|
||||
{
|
||||
$path = PluginManager::instance()->findByIdentifier($this->testPlugin)->getPluginPath();
|
||||
$configPath = $path . '/vite.config.mjs';
|
||||
$packageJson = $path . '/package.json';
|
||||
|
||||
// Check file does not exist
|
||||
$this->assertFileNotExists($configPath);
|
||||
|
||||
// Run the config command to generate the vite config with vue
|
||||
$this->artisan('vite:create', [
|
||||
'packageName' => $this->testPlugin,
|
||||
'--tailwind' => true,
|
||||
'--vue' => true,
|
||||
'--no-stubs' => true,
|
||||
])
|
||||
->assertExitCode(0);
|
||||
|
||||
// Check files are created correctly
|
||||
$this->assertFileExists($configPath);
|
||||
$this->assertFileExists($packageJson);
|
||||
$this->assertFileExists($path . '/tailwind.config.js');
|
||||
$this->assertFileExists($path . '/postcss.config.mjs');
|
||||
|
||||
// Get the contents of the package.json
|
||||
$json = json_decode(File::get($packageJson));
|
||||
|
||||
// Check tailwind & vue are required
|
||||
$this->assertTrue(isset($json->devDependencies->tailwindcss));
|
||||
$this->assertTrue(isset($json->devDependencies->vue));
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
$path = PluginManager::instance()->findByIdentifier($this->testPlugin)->getPluginPath();
|
||||
|
||||
$files = [
|
||||
$path . '/vite.config.mjs',
|
||||
$path . '/package.json',
|
||||
$path . '/tailwind.config.js',
|
||||
$path . '/postcss.config.mjs',
|
||||
];
|
||||
|
||||
foreach ($files as $file) {
|
||||
if (File::exists($file)) {
|
||||
File::delete($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
223
modules/system/tests/console/asset/vite/ViteInstallTest.php
Normal file
223
modules/system/tests/console/asset/vite/ViteInstallTest.php
Normal file
@@ -0,0 +1,223 @@
|
||||
<?php
|
||||
|
||||
namespace System\Tests\Console\Asset\Vite;
|
||||
|
||||
use System\Classes\Asset\PackageManager;
|
||||
use System\Tests\Bootstrap\TestCase;
|
||||
use Winter\Storm\Exception\SystemException;
|
||||
use Winter\Storm\Support\Facades\File;
|
||||
|
||||
class ViteInstallTest extends TestCase
|
||||
{
|
||||
protected string $jsonPath;
|
||||
protected string $lockPath;
|
||||
protected string $backupPath;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
if (!File::exists(base_path('node_modules'))) {
|
||||
$this->markTestSkipped('This test requires node_modules to be installed');
|
||||
}
|
||||
|
||||
// Define some helpful paths
|
||||
$this->fixturePath = base_path('modules/system/tests');
|
||||
$this->jsonPath = $this->fixturePath . '/package.json';
|
||||
$this->lockPath = $this->fixturePath . '/package-lock.json';
|
||||
$this->backupPath = $this->fixturePath . '/package-testing.json';
|
||||
|
||||
// Add our testing theme because it won't be auto discovered
|
||||
PackageManager::instance()->registerPackage(
|
||||
'theme-assettest',
|
||||
base_path('modules/system/tests/fixtures/themes/assettest/vite.config.mjs'),
|
||||
'vite'
|
||||
);
|
||||
PackageManager::instance()->registerPackage(
|
||||
'theme-npmtest',
|
||||
base_path('modules/system/tests/fixtures/themes/npmtest/vite.config.mjs'),
|
||||
'vite'
|
||||
);
|
||||
}
|
||||
|
||||
public function testViteInstallMissingPackageJson(): void
|
||||
{
|
||||
$this->artisan('vite:install', [
|
||||
'assetPackage' => ['theme-assettest'],
|
||||
'--package-json' => '/some/file',
|
||||
'--no-install' => true
|
||||
])
|
||||
->expectsOutputToContain('The supplied --package-json path does not exist.')
|
||||
->assertExitCode(1);
|
||||
}
|
||||
|
||||
public function testViteInstallSinglePackage(): void
|
||||
{
|
||||
$this->withPackageJsonRestore(function () {
|
||||
$this->artisan('vite:install', [
|
||||
'assetPackage' => ['theme-assettest'],
|
||||
'--package-json' => $this->jsonPath,
|
||||
'--no-install' => true
|
||||
])
|
||||
->expectsQuestion('vite was not found as a dependency in package.json, would you like to add it?', true)
|
||||
->expectsQuestion('laravel-vite-plugin was not found as a dependency in package.json, would you like to add it?', true)
|
||||
->expectsOutput('Adding theme-assettest (modules/system/tests/fixtures/themes/assettest) to the workspaces.packages property in package.json')
|
||||
->assertExitCode(0);
|
||||
|
||||
$this->assertFileExists($this->jsonPath);
|
||||
$packageJson = json_decode(File::get($this->jsonPath), JSON_OBJECT_AS_ARRAY);
|
||||
$this->assertArrayHasKey('devDependencies', $packageJson);
|
||||
$this->assertArrayHasKey('vite', $packageJson['devDependencies']);
|
||||
$this->assertArrayHasKey('laravel-vite-plugin', $packageJson['devDependencies']);
|
||||
|
||||
$this->assertArrayHasKey('workspaces', $packageJson);
|
||||
$this->assertArrayHasKey('packages', $packageJson['workspaces']);
|
||||
$this->assertContains('modules/system/tests/fixtures/themes/assettest', $packageJson['workspaces']['packages']);
|
||||
});
|
||||
}
|
||||
|
||||
public function testViteInstallMultiplePackages(): void
|
||||
{
|
||||
$this->withPackageJsonRestore(function () {
|
||||
$this->artisan('vite:install', [
|
||||
'assetPackage' => ['theme-assettest', 'theme-npmtest'],
|
||||
'--package-json' => $this->jsonPath,
|
||||
'--no-install' => true
|
||||
])
|
||||
->expectsQuestion('vite was not found as a dependency in package.json, would you like to add it?', true)
|
||||
->expectsQuestion('laravel-vite-plugin was not found as a dependency in package.json, would you like to add it?', true)
|
||||
->expectsOutput('Adding theme-assettest (modules/system/tests/fixtures/themes/assettest) to the workspaces.packages property in package.json')
|
||||
->expectsOutput('Adding theme-npmtest (modules/system/tests/fixtures/themes/npmtest) to the workspaces.packages property in package.json')
|
||||
->assertExitCode(0);
|
||||
|
||||
$this->assertFileExists($this->jsonPath);
|
||||
$packageJson = json_decode(File::get($this->jsonPath), JSON_OBJECT_AS_ARRAY);
|
||||
$this->assertArrayHasKey('devDependencies', $packageJson);
|
||||
$this->assertArrayHasKey('vite', $packageJson['devDependencies']);
|
||||
$this->assertArrayHasKey('laravel-vite-plugin', $packageJson['devDependencies']);
|
||||
|
||||
$this->assertArrayHasKey('workspaces', $packageJson);
|
||||
$this->assertArrayHasKey('packages', $packageJson['workspaces']);
|
||||
$this->assertContains('modules/system/tests/fixtures/themes/assettest', $packageJson['workspaces']['packages']);
|
||||
$this->assertContains('modules/system/tests/fixtures/themes/npmtest', $packageJson['workspaces']['packages']);
|
||||
});
|
||||
}
|
||||
|
||||
public function testViteInstallMissingPackage(): void
|
||||
{
|
||||
// We should receive an exception for a missing package
|
||||
$this->withPackageJsonRestore(function () {
|
||||
$this->expectException(SystemException::class);
|
||||
$this->expectExceptionMessage('PackageNotFoundException: The package `theme-assettest2` does not exist.');
|
||||
|
||||
$this->artisan('vite:install', [
|
||||
'assetPackage' => ['theme-assettest2'],
|
||||
'--package-json' => $this->jsonPath,
|
||||
'--no-install' => true
|
||||
])
|
||||
->assertExitCode(1);
|
||||
});
|
||||
}
|
||||
|
||||
public function testViteInstallRelativePath(): void
|
||||
{
|
||||
$this->withPackageJsonRestore(function () {
|
||||
$this->artisan('vite:install', [
|
||||
'assetPackage' => ['theme-assettest'],
|
||||
'--package-json' => 'modules/system/tests/package.json',
|
||||
'--no-install' => true
|
||||
])
|
||||
->expectsQuestion('vite was not found as a dependency in package.json, would you like to add it?', true)
|
||||
->expectsQuestion('laravel-vite-plugin was not found as a dependency in package.json, would you like to add it?', true)
|
||||
->expectsOutput('Adding theme-assettest (modules/system/tests/fixtures/themes/assettest) to the workspaces.packages property in package.json')
|
||||
->assertExitCode(0);
|
||||
});
|
||||
}
|
||||
|
||||
public function testViteInstallIgnoredPackage(): void
|
||||
{
|
||||
$this->withPackageJsonRestore(function () {
|
||||
$packageJson = json_decode(File::get($this->jsonPath), JSON_OBJECT_AS_ARRAY);
|
||||
$packageJson['workspaces'] = [
|
||||
'ignoredPackages' => [
|
||||
'modules/system/tests/fixtures/themes/assettest'
|
||||
]
|
||||
];
|
||||
|
||||
File::put($this->jsonPath, json_encode($packageJson, JSON_PRETTY_PRINT));
|
||||
|
||||
$this->artisan('vite:install', [
|
||||
'assetPackage' => ['theme-assettest'],
|
||||
'--package-json' => $this->jsonPath,
|
||||
'--no-install' => true
|
||||
])
|
||||
->expectsQuestion('vite was not found as a dependency in package.json, would you like to add it?', false)
|
||||
->expectsQuestion('laravel-vite-plugin was not found as a dependency in package.json, would you like to add it?', false)
|
||||
->expectsOutput('The requested package theme-assettest (modules/system/tests/fixtures/themes/assettest) is ignored, remove it from package.json to continue.')
|
||||
->assertExitCode(0);
|
||||
|
||||
$packageJson = json_decode(File::get($this->jsonPath), JSON_OBJECT_AS_ARRAY);
|
||||
$this->assertArrayHasKey('workspaces', $packageJson);
|
||||
$this->assertArrayNotHasKey('packages', $packageJson['workspaces']);
|
||||
$this->assertArrayNotHasKey('dependencies', $packageJson);
|
||||
$this->assertArrayNotHasKey('devDependencies', $packageJson);
|
||||
});
|
||||
}
|
||||
|
||||
public function testViteInstallWithNpmInstall(): void
|
||||
{
|
||||
$this->withPackageJsonRestore(function () {
|
||||
$this->assertDirectoryDoesNotExist($this->fixturePath . '/node_modules');
|
||||
|
||||
$this->artisan('vite:install', [
|
||||
'assetPackage' => ['theme-assettest'],
|
||||
'--package-json' => $this->jsonPath,
|
||||
'--disable-tty' => true
|
||||
])
|
||||
->expectsQuestion('vite was not found as a dependency in package.json, would you like to add it?', true)
|
||||
->expectsQuestion('laravel-vite-plugin was not found as a dependency in package.json, would you like to add it?', true)
|
||||
->expectsOutput('Adding theme-assettest (modules/system/tests/fixtures/themes/assettest) to the workspaces.packages property in package.json')
|
||||
->expectsOutputToContain('packages, and audited') // output from npm i
|
||||
->assertExitCode(0);
|
||||
|
||||
$this->assertFileExists($this->jsonPath);
|
||||
$packageJson = json_decode(File::get($this->jsonPath), JSON_OBJECT_AS_ARRAY);
|
||||
$this->assertArrayHasKey('devDependencies', $packageJson);
|
||||
$this->assertArrayHasKey('vite', $packageJson['devDependencies']);
|
||||
$this->assertArrayHasKey('laravel-vite-plugin', $packageJson['devDependencies']);
|
||||
|
||||
$this->assertArrayHasKey('workspaces', $packageJson);
|
||||
$this->assertArrayHasKey('packages', $packageJson['workspaces']);
|
||||
$this->assertContains('modules/system/tests/fixtures/themes/assettest', $packageJson['workspaces']['packages']);
|
||||
|
||||
$this->assertFileExists($this->lockPath);
|
||||
|
||||
$this->assertDirectoryExists($this->fixturePath . '/node_modules');
|
||||
$this->assertDirectoryExists($this->fixturePath . '/node_modules/vite');
|
||||
$this->assertDirectoryExists($this->fixturePath . '/node_modules/laravel-vite-plugin');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to run test logic and handle restoring package.json file after
|
||||
*/
|
||||
protected function withPackageJsonRestore(callable $callback): void
|
||||
{
|
||||
File::copy($this->backupPath, $this->jsonPath);
|
||||
$callback();
|
||||
File::delete($this->jsonPath);
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
if (File::isDirectory($this->fixturePath . '/node_modules')) {
|
||||
File::deleteDirectory($this->fixturePath . '/node_modules');
|
||||
}
|
||||
|
||||
if (File::exists($this->lockPath)) {
|
||||
File::delete($this->lockPath);
|
||||
}
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
}
|
||||
9
modules/system/tests/fixtures/config/app.php
vendored
Normal file
9
modules/system/tests/fixtures/config/app.php
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
// Fixture used for `winter:env` unit tests in `tests/unit/system/console/WinterEnvTest.php
|
||||
|
||||
return [
|
||||
'debug' => true,
|
||||
'url' => 'https://env-test.localhost',
|
||||
'key' => 'CHANGE_ME!!!!!!!!!!!!!!!!!!!!!!!',
|
||||
'timezone' => 'UTC',
|
||||
];
|
||||
6
modules/system/tests/fixtures/config/cache.php
vendored
Normal file
6
modules/system/tests/fixtures/config/cache.php
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
// Fixture used for `winter:env` unit tests in `tests/unit/system/console/WinterEnvTest.php
|
||||
|
||||
return [
|
||||
'default' => 'file',
|
||||
];
|
||||
10
modules/system/tests/fixtures/config/cms.php
vendored
Normal file
10
modules/system/tests/fixtures/config/cms.php
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
// Fixture used for `winter:env` unit tests in `tests/unit/system/console/WinterEnvTest.php
|
||||
|
||||
return [
|
||||
'enableRoutesCache' => false,
|
||||
'enableAssetCache' => false,
|
||||
'databaseTemplates' => false,
|
||||
'linkPolicy' => 'detect',
|
||||
'enableCsrfProtection' => true,
|
||||
];
|
||||
16
modules/system/tests/fixtures/config/database.php
vendored
Normal file
16
modules/system/tests/fixtures/config/database.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
// Fixture used for `winter:env` unit tests in `tests/unit/system/console/WinterEnvTest.php
|
||||
|
||||
return [
|
||||
'default' => 'mysql',
|
||||
'connections' => [
|
||||
'mysql' => [
|
||||
'host' => 'localhost',
|
||||
'port' => 3306,
|
||||
'database' => 'data#base',
|
||||
'username' => 'teal\'c',
|
||||
'password' => 'test"quotes\'test',
|
||||
],
|
||||
],
|
||||
'useConfigForTesting' => false,
|
||||
];
|
||||
11
modules/system/tests/fixtures/config/mail.php
vendored
Normal file
11
modules/system/tests/fixtures/config/mail.php
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
// Fixture used for `winter:env` unit tests in `tests/unit/system/console/WinterEnvTest.php
|
||||
|
||||
return [
|
||||
'default' => 'smtp',
|
||||
'host' => 'smtp.mailgun.org',
|
||||
'port' => 587,
|
||||
'encryption' => 'tls',
|
||||
'username' => null,
|
||||
'password' => null,
|
||||
];
|
||||
6
modules/system/tests/fixtures/config/queue.php
vendored
Normal file
6
modules/system/tests/fixtures/config/queue.php
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
// Fixture used for `winter:env` unit tests in `tests/unit/system/console/WinterEnvTest.php
|
||||
|
||||
return [
|
||||
'default' => 'sync',
|
||||
];
|
||||
6
modules/system/tests/fixtures/config/session.php
vendored
Normal file
6
modules/system/tests/fixtures/config/session.php
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
// Fixture used for `winter:env` unit tests in `tests/unit/system/console/WinterEnvTest.php
|
||||
|
||||
return [
|
||||
'driver' => 'file',
|
||||
];
|
||||
2
modules/system/tests/fixtures/manifest/1_0_0/modules/test/file1.php
vendored
Normal file
2
modules/system/tests/fixtures/manifest/1_0_0/modules/test/file1.php
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// file1.php - version 1.
|
||||
2
modules/system/tests/fixtures/manifest/1_0_1/modules/test/file1.php
vendored
Normal file
2
modules/system/tests/fixtures/manifest/1_0_1/modules/test/file1.php
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// file1.php - version 1.
|
||||
2
modules/system/tests/fixtures/manifest/1_0_1/modules/test/file2.php
vendored
Normal file
2
modules/system/tests/fixtures/manifest/1_0_1/modules/test/file2.php
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// file2.php - version 1.
|
||||
2
modules/system/tests/fixtures/manifest/1_0_1/modules/test2/file1.php
vendored
Normal file
2
modules/system/tests/fixtures/manifest/1_0_1/modules/test2/file1.php
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// file1.php - version 1 / test2.
|
||||
2
modules/system/tests/fixtures/manifest/1_0_2/modules/test/file2.php
vendored
Normal file
2
modules/system/tests/fixtures/manifest/1_0_2/modules/test/file2.php
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// file2.php - version 2.
|
||||
2
modules/system/tests/fixtures/manifest/1_0_2/modules/test/file3.php
vendored
Normal file
2
modules/system/tests/fixtures/manifest/1_0_2/modules/test/file3.php
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// file3.php - version 1.
|
||||
2
modules/system/tests/fixtures/manifest/1_0_2/modules/test2/file1.php
vendored
Normal file
2
modules/system/tests/fixtures/manifest/1_0_2/modules/test2/file1.php
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// file1.php - version 1 / test2.
|
||||
2
modules/system/tests/fixtures/manifest/1_0_3/modules/test/file2.php
vendored
Normal file
2
modules/system/tests/fixtures/manifest/1_0_3/modules/test/file2.php
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// file2.php - version 2.
|
||||
2
modules/system/tests/fixtures/manifest/1_0_3/modules/test2/file1.php
vendored
Normal file
2
modules/system/tests/fixtures/manifest/1_0_3/modules/test2/file1.php
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// file1.php - version 3 / test2.
|
||||
2
modules/system/tests/fixtures/manifest/1_1_0/modules/test/file3.php
vendored
Normal file
2
modules/system/tests/fixtures/manifest/1_1_0/modules/test/file3.php
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// file3.php - version 2.
|
||||
2
modules/system/tests/fixtures/manifest/1_1_0/modules/test/file4.php
vendored
Normal file
2
modules/system/tests/fixtures/manifest/1_1_0/modules/test/file4.php
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// file4.php - version 1.
|
||||
2
modules/system/tests/fixtures/manifest/1_1_0/modules/test2/file1.php
vendored
Normal file
2
modules/system/tests/fixtures/manifest/1_1_0/modules/test2/file1.php
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// file1.php - version 2 / test2.
|
||||
2
modules/system/tests/fixtures/manifest/1_1_0/modules/test3/file1.php
vendored
Normal file
2
modules/system/tests/fixtures/manifest/1_1_0/modules/test3/file1.php
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// file1.php - version 1 / test3.
|
||||
2
modules/system/tests/fixtures/manifest/1_1_1/modules/test/file3.php
vendored
Normal file
2
modules/system/tests/fixtures/manifest/1_1_1/modules/test/file3.php
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// file3.php - version 2.
|
||||
2
modules/system/tests/fixtures/manifest/1_1_1/modules/test/file4.php
vendored
Normal file
2
modules/system/tests/fixtures/manifest/1_1_1/modules/test/file4.php
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// file4.php - version 1.
|
||||
2
modules/system/tests/fixtures/manifest/1_1_1/modules/test2/file1.php
vendored
Normal file
2
modules/system/tests/fixtures/manifest/1_1_1/modules/test2/file1.php
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// file1.php - version 3 / test2.
|
||||
2
modules/system/tests/fixtures/manifest/1_1_1/modules/test3/file1.php
vendored
Normal file
2
modules/system/tests/fixtures/manifest/1_1_1/modules/test3/file1.php
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// file1.php - version 2 / test3.
|
||||
2
modules/system/tests/fixtures/manifest/1_1_1/modules/test3/file2.php
vendored
Normal file
2
modules/system/tests/fixtures/manifest/1_1_1/modules/test3/file2.php
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// file2.php - version 1 / test3.
|
||||
5
modules/system/tests/fixtures/manifest/forks.json
vendored
Normal file
5
modules/system/tests/fixtures/manifest/forks.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"forks": {
|
||||
"1.1.0": "1.0.2"
|
||||
}
|
||||
}
|
||||
1
modules/system/tests/fixtures/media/text.txt
vendored
Normal file
1
modules/system/tests/fixtures/media/text.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
THIS IS A TEXT DOCUMENT
|
||||
BIN
modules/system/tests/fixtures/media/winter space.png
vendored
Normal file
BIN
modules/system/tests/fixtures/media/winter space.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.3 KiB |
BIN
modules/system/tests/fixtures/media/winter.png
vendored
Normal file
BIN
modules/system/tests/fixtures/media/winter.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.3 KiB |
12
modules/system/tests/fixtures/npm/package-abc.json
vendored
Normal file
12
modules/system/tests/fixtures/npm/package-abc.json
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"laravel-mix": "^6.0.41"
|
||||
},
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
"modules/system/tests/fixtures/plugins/mix/testa",
|
||||
"modules/system/tests/fixtures/plugins/mix/testb",
|
||||
"modules/system/tests/fixtures/plugins/mix/testc"
|
||||
]
|
||||
}
|
||||
}
|
||||
11
modules/system/tests/fixtures/npm/package-ac.json
vendored
Normal file
11
modules/system/tests/fixtures/npm/package-ac.json
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"laravel-mix": "^6.0.41"
|
||||
},
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
"modules/system/tests/fixtures/plugins/mix/testa",
|
||||
"modules/system/tests/fixtures/plugins/mix/testc"
|
||||
]
|
||||
}
|
||||
}
|
||||
8
modules/system/tests/fixtures/npm/package-corrupt.json
vendored
Normal file
8
modules/system/tests/fixtures/npm/package-corrupt.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
"plugins/winter/demo",
|
||||
"themes/demo"
|
||||
]
|
||||
},
|
||||
"dependencies":
|
||||
24
modules/system/tests/fixtures/npm/package-test.json
vendored
Normal file
24
modules/system/tests/fixtures/npm/package-test.json
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
"plugins/winter/demo",
|
||||
"themes/demo"
|
||||
],
|
||||
"ignoredPackages": [
|
||||
"modules/backend",
|
||||
"modules/system"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"example": "^2.0.1",
|
||||
"test": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"test-dev": "^3.0.2"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "testing",
|
||||
"example": "example test",
|
||||
"foo": "bar ./test"
|
||||
}
|
||||
}
|
||||
12
modules/system/tests/fixtures/npm/package-vitetheme.json
vendored
Normal file
12
modules/system/tests/fixtures/npm/package-vitetheme.json
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"type": "module",
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
"modules/system/tests/fixtures/themes/assettest"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"laravel-vite-plugin": "^1.0.2",
|
||||
"vite": "^5.2.11"
|
||||
}
|
||||
}
|
||||
15
modules/system/tests/fixtures/plugins/database/tester/Plugin.php
vendored
Normal file
15
modules/system/tests/fixtures/plugins/database/tester/Plugin.php
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php namespace Database\Tester;
|
||||
|
||||
use System\Classes\PluginBase;
|
||||
|
||||
class Plugin extends PluginBase
|
||||
{
|
||||
public function pluginDetails()
|
||||
{
|
||||
return [
|
||||
'name' => 'Database Tester Plugin',
|
||||
'description' => 'Plugin for loading tests that involve the database.',
|
||||
'author' => 'Alexey Bobkov, Samuel Georges'
|
||||
];
|
||||
}
|
||||
}
|
||||
BIN
modules/system/tests/fixtures/plugins/database/tester/assets/images/avatar.png
vendored
Normal file
BIN
modules/system/tests/fixtures/plugins/database/tester/assets/images/avatar.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
68
modules/system/tests/fixtures/plugins/database/tester/models/Author.php
vendored
Normal file
68
modules/system/tests/fixtures/plugins/database/tester/models/Author.php
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php namespace Database\Tester\Models;
|
||||
|
||||
use Model;
|
||||
|
||||
class Author extends Model
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string The database table used by the model.
|
||||
*/
|
||||
public $table = 'database_tester_authors';
|
||||
|
||||
/**
|
||||
* @var array Guarded fields
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* @var array Relations
|
||||
*/
|
||||
public $belongsTo = [
|
||||
'user' => ['Database\Tester\Models\User', 'delete' => true],
|
||||
'country' => ['Database\Tester\Models\Country'],
|
||||
'user_soft' => ['Database\Tester\Models\SoftDeleteUser', 'key' => 'user_id', 'softDelete' => true],
|
||||
];
|
||||
|
||||
public $hasMany = [
|
||||
'posts' => 'Database\Tester\Models\Post',
|
||||
];
|
||||
|
||||
public $hasOne = [
|
||||
'phone' => 'Database\Tester\Models\Phone',
|
||||
];
|
||||
|
||||
public $belongsToMany = [
|
||||
'roles' => [
|
||||
'Database\Tester\Models\Role',
|
||||
'table' => 'database_tester_authors_roles'
|
||||
],
|
||||
'executive_authors' => [
|
||||
'Database\Tester\Models\Role',
|
||||
'table' => 'database_tester_authors_roles',
|
||||
'conditions' => 'is_executive = 1'
|
||||
],
|
||||
];
|
||||
|
||||
public $morphMany = [
|
||||
'event_log' => ['Database\Tester\Models\EventLog', 'name' => 'related', 'delete' => true, 'softDelete' => true],
|
||||
];
|
||||
|
||||
public $morphOne = [
|
||||
'meta' => ['Database\Tester\Models\Meta', 'name' => 'taggable'],
|
||||
];
|
||||
|
||||
public $morphToMany = [
|
||||
'tags' => [
|
||||
'Database\Tester\Models\Tag',
|
||||
'name' => 'taggable',
|
||||
'table' => 'database_tester_taggables',
|
||||
'pivot' => ['added_by']
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
class SoftDeleteAuthor extends Author
|
||||
{
|
||||
use \Winter\Storm\Database\Traits\SoftDelete;
|
||||
}
|
||||
40
modules/system/tests/fixtures/plugins/database/tester/models/Category.php
vendored
Normal file
40
modules/system/tests/fixtures/plugins/database/tester/models/Category.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php namespace Database\Tester\Models;
|
||||
|
||||
use Model;
|
||||
|
||||
class Category extends Model
|
||||
{
|
||||
/**
|
||||
* @var string The database table used by the model.
|
||||
*/
|
||||
public $table = 'database_tester_categories';
|
||||
|
||||
public $belongsToMany = [
|
||||
'posts' => [
|
||||
'Database\Tester\Models\Post',
|
||||
'table' => 'database_tester_categories_posts',
|
||||
'pivot' => ['category_name', 'post_name']
|
||||
]
|
||||
];
|
||||
|
||||
public function getCustomNameAttribute()
|
||||
{
|
||||
return $this->name.' (#'.$this->id.')';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class CategorySimple extends Category
|
||||
{
|
||||
use \Winter\Storm\Database\Traits\SimpleTree;
|
||||
}
|
||||
|
||||
class CategoryNested extends Category
|
||||
{
|
||||
use \Winter\Storm\Database\Traits\NestedTree;
|
||||
|
||||
/**
|
||||
* @var string The database table used by the model.
|
||||
*/
|
||||
public $table = 'database_tester_categories_nested';
|
||||
}
|
||||
35
modules/system/tests/fixtures/plugins/database/tester/models/Country.php
vendored
Normal file
35
modules/system/tests/fixtures/plugins/database/tester/models/Country.php
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php namespace Database\Tester\Models;
|
||||
|
||||
use Model;
|
||||
|
||||
class Country extends Model
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string The database table used by the model.
|
||||
*/
|
||||
public $table = 'database_tester_countries';
|
||||
|
||||
/**
|
||||
* @var array Guarded fields
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
public $hasMany = [
|
||||
'users' => [
|
||||
'Database\Tester\Models\User',
|
||||
],
|
||||
];
|
||||
|
||||
public $hasManyThrough = [
|
||||
'posts' => [
|
||||
'Database\Tester\Models\Post',
|
||||
'through' => 'Database\Tester\Models\Author',
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
class SoftDeleteCountry extends Country
|
||||
{
|
||||
use \Winter\Storm\Database\Traits\SoftDelete;
|
||||
}
|
||||
30
modules/system/tests/fixtures/plugins/database/tester/models/EventLog.php
vendored
Normal file
30
modules/system/tests/fixtures/plugins/database/tester/models/EventLog.php
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php namespace Database\Tester\Models;
|
||||
|
||||
use Model;
|
||||
|
||||
class EventLog extends Model
|
||||
{
|
||||
use \Winter\Storm\Database\Traits\SoftDelete;
|
||||
|
||||
/**
|
||||
* @var string The database table used by the model.
|
||||
*/
|
||||
public $table = 'database_tester_event_log';
|
||||
|
||||
/**
|
||||
* @var array Guarded fields
|
||||
*/
|
||||
protected $guarded = ['*'];
|
||||
|
||||
/**
|
||||
* @var array Fillable fields
|
||||
*/
|
||||
protected $fillable = [];
|
||||
|
||||
/**
|
||||
* @var array Relations
|
||||
*/
|
||||
public $morphTo = [
|
||||
'related' => []
|
||||
];
|
||||
}
|
||||
24
modules/system/tests/fixtures/plugins/database/tester/models/Meta.php
vendored
Normal file
24
modules/system/tests/fixtures/plugins/database/tester/models/Meta.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php namespace Database\Tester\Models;
|
||||
|
||||
use Model;
|
||||
|
||||
class Meta extends Model
|
||||
{
|
||||
public $table = 'database_tester_meta';
|
||||
|
||||
public $timestamps = false;
|
||||
|
||||
public $morphTo = [
|
||||
'taggable' => []
|
||||
];
|
||||
|
||||
public $fillable = [
|
||||
'meta_title',
|
||||
'meta_description',
|
||||
'meta_keywords',
|
||||
'canonical_url',
|
||||
'redirect_url',
|
||||
'robot_index',
|
||||
'robot_follow'
|
||||
];
|
||||
}
|
||||
29
modules/system/tests/fixtures/plugins/database/tester/models/Phone.php
vendored
Normal file
29
modules/system/tests/fixtures/plugins/database/tester/models/Phone.php
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php namespace Database\Tester\Models;
|
||||
|
||||
use Model;
|
||||
|
||||
class Phone extends Model
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string The database table used by the model.
|
||||
*/
|
||||
public $table = 'database_tester_phones';
|
||||
|
||||
/**
|
||||
* @var array Guarded fields
|
||||
*/
|
||||
protected $guarded = ['*'];
|
||||
|
||||
/**
|
||||
* @var array Fillable fields
|
||||
*/
|
||||
protected $fillable = [];
|
||||
|
||||
/**
|
||||
* @var array Relations
|
||||
*/
|
||||
public $belongsTo = [
|
||||
'author' => 'Database\Tester\Models\Author',
|
||||
];
|
||||
}
|
||||
151
modules/system/tests/fixtures/plugins/database/tester/models/Post.php
vendored
Normal file
151
modules/system/tests/fixtures/plugins/database/tester/models/Post.php
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
<?php namespace Database\Tester\Models;
|
||||
|
||||
use Model;
|
||||
|
||||
class Post extends Model
|
||||
{
|
||||
/**
|
||||
* @var string The database table used by the model.
|
||||
*/
|
||||
public $table = 'database_tester_posts';
|
||||
|
||||
/**
|
||||
* @var array Guarded fields
|
||||
*/
|
||||
protected $guarded = ['*'];
|
||||
|
||||
/**
|
||||
* @var array Fillable fields
|
||||
*/
|
||||
protected $fillable = [];
|
||||
|
||||
/**
|
||||
* @var array Relations
|
||||
*/
|
||||
public $belongsTo = [
|
||||
'author' => 'Database\Tester\Models\Author',
|
||||
];
|
||||
|
||||
public $belongsToMany = [
|
||||
'categories' => [
|
||||
'Database\Tester\Models\Category',
|
||||
'table' => 'database_tester_categories_posts',
|
||||
'pivot' => ['category_name', 'post_name']
|
||||
]
|
||||
];
|
||||
|
||||
public $morphMany = [
|
||||
'event_log' => ['Database\Tester\Models\EventLog', 'name' => 'related', 'delete' => true, 'softDelete' => true],
|
||||
];
|
||||
|
||||
public $morphOne = [
|
||||
'meta' => ['Database\Tester\Models\Meta', 'name' => 'taggable'],
|
||||
];
|
||||
|
||||
public $morphToMany = [
|
||||
'tags' => [
|
||||
'Database\Tester\Models\Tag',
|
||||
'name' => 'taggable',
|
||||
'table' => 'database_tester_taggables',
|
||||
'pivot' => ['added_by']
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
class NullablePost extends Post
|
||||
{
|
||||
use \Winter\Storm\Database\Traits\Nullable;
|
||||
|
||||
/**
|
||||
* @var array Guarded fields
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* @var array List of attributes to nullify
|
||||
*/
|
||||
protected $nullable = [
|
||||
'author_nickname',
|
||||
];
|
||||
}
|
||||
|
||||
class SluggablePost extends Post
|
||||
{
|
||||
use \Winter\Storm\Database\Traits\Sluggable;
|
||||
|
||||
/**
|
||||
* @var array Guarded fields
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* @var array List of attributes to automatically generate unique URL names (slugs) for.
|
||||
*/
|
||||
protected $slugs = [
|
||||
'slug' => 'title',
|
||||
'long_slug' => ['title', 'description']
|
||||
];
|
||||
}
|
||||
|
||||
class RevisionablePost extends Post
|
||||
{
|
||||
use \Winter\Storm\Database\Traits\Revisionable;
|
||||
use \Winter\Storm\Database\Traits\SoftDelete;
|
||||
|
||||
/**
|
||||
* @var array Guarded fields
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* @var array Dates
|
||||
*/
|
||||
protected $dates = ['published_at', 'deleted_at'];
|
||||
|
||||
/**
|
||||
* @var array Monitor these attributes for changes.
|
||||
*/
|
||||
protected $revisionable = [
|
||||
'title',
|
||||
'slug',
|
||||
'description',
|
||||
'is_published',
|
||||
'published_at',
|
||||
'deleted_at'
|
||||
];
|
||||
|
||||
/**
|
||||
* @var int Maximum number of revision records to keep.
|
||||
*/
|
||||
public $revisionableLimit = 8;
|
||||
|
||||
/**
|
||||
* @var array Relations
|
||||
*/
|
||||
public $morphMany = [
|
||||
'revision_history' => ['System\Models\Revision', 'name' => 'revisionable']
|
||||
];
|
||||
|
||||
/**
|
||||
* The user who made the revision.
|
||||
*/
|
||||
public function getRevisionableUser()
|
||||
{
|
||||
return 7;
|
||||
}
|
||||
}
|
||||
|
||||
class ValidationPost extends Post
|
||||
{
|
||||
use \Winter\Storm\Database\Traits\Validation;
|
||||
|
||||
/**
|
||||
* @var array Guarded fields
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
public $rules = [
|
||||
'title' => 'required|min:3|max:255',
|
||||
'slug' => ['required', 'regex:/^[a-z0-9\/\:_\-\*\[\]\+\?\|]*$/i', 'unique:database_tester_posts'],
|
||||
];
|
||||
}
|
||||
34
modules/system/tests/fixtures/plugins/database/tester/models/Role.php
vendored
Normal file
34
modules/system/tests/fixtures/plugins/database/tester/models/Role.php
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php namespace Database\Tester\Models;
|
||||
|
||||
use Model;
|
||||
|
||||
/**
|
||||
* Role Model
|
||||
*/
|
||||
class Role extends Model
|
||||
{
|
||||
/**
|
||||
* @var string The database table used by the model.
|
||||
*/
|
||||
public $table = 'database_tester_roles';
|
||||
|
||||
/**
|
||||
* @var array Guarded fields
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* @var array Fillable fields
|
||||
*/
|
||||
protected $fillable = [];
|
||||
|
||||
/**
|
||||
* @var array Relations
|
||||
*/
|
||||
public $belongsToMany = [
|
||||
'authors' => [
|
||||
'Database\Tester\Models\User',
|
||||
'table' => 'database_tester_authors_roles'
|
||||
],
|
||||
];
|
||||
}
|
||||
36
modules/system/tests/fixtures/plugins/database/tester/models/Tag.php
vendored
Normal file
36
modules/system/tests/fixtures/plugins/database/tester/models/Tag.php
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php namespace Database\Tester\Models;
|
||||
|
||||
use Model;
|
||||
|
||||
class Tag extends Model
|
||||
{
|
||||
/**
|
||||
* @var string The database table used by the model.
|
||||
*/
|
||||
public $table = 'database_tester_tags';
|
||||
|
||||
/**
|
||||
* @var array Guarded fields
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* @var array Fillable fields
|
||||
*/
|
||||
protected $fillable = [];
|
||||
|
||||
public $morphedByMany = [
|
||||
'authors' => [
|
||||
'Database\Tester\Models\Author',
|
||||
'name' => 'taggable',
|
||||
'table' => 'database_tester_taggables',
|
||||
'pivot' => ['added_by'],
|
||||
],
|
||||
'posts' => [
|
||||
'Database\Tester\Models\Post',
|
||||
'name' => 'taggable',
|
||||
'table' => 'database_tester_taggables',
|
||||
'pivot' => ['added_by'],
|
||||
],
|
||||
];
|
||||
}
|
||||
69
modules/system/tests/fixtures/plugins/database/tester/models/User.php
vendored
Normal file
69
modules/system/tests/fixtures/plugins/database/tester/models/User.php
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php namespace Database\Tester\Models;
|
||||
|
||||
use Model;
|
||||
|
||||
class User extends Model
|
||||
{
|
||||
/**
|
||||
* @var string The database table used by the model.
|
||||
*/
|
||||
public $table = 'database_tester_users';
|
||||
|
||||
/**
|
||||
* @var array Guarded fields
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* @var array Relations
|
||||
*/
|
||||
public $hasOne = [
|
||||
'author' => [
|
||||
'Database\Tester\Models\Author',
|
||||
]
|
||||
];
|
||||
|
||||
public $hasOneThrough = [
|
||||
'phone' => [
|
||||
'Database\Tester\Models\Phone',
|
||||
'through' => 'Database\Tester\Models\Author',
|
||||
],
|
||||
];
|
||||
|
||||
public $attachOne = [
|
||||
'avatar' => 'System\Models\File'
|
||||
];
|
||||
|
||||
public $attachMany = [
|
||||
'photos' => 'System\Models\File'
|
||||
];
|
||||
}
|
||||
|
||||
class SoftDeleteUser extends User
|
||||
{
|
||||
use \Winter\Storm\Database\Traits\SoftDelete;
|
||||
}
|
||||
|
||||
class UserWithAuthor extends User
|
||||
{
|
||||
public $hasOne = [
|
||||
'author' => ['Database\Tester\Models\Author', 'key' => 'user_id', 'delete' => true],
|
||||
];
|
||||
}
|
||||
|
||||
class UserWithSoftAuthor extends User
|
||||
{
|
||||
public $hasOne = [
|
||||
'author' => ['Database\Tester\Models\SoftDeleteAuthor', 'key' => 'user_id', 'softDelete' => true],
|
||||
];
|
||||
}
|
||||
|
||||
class UserWithAuthorAndSoftDelete extends UserWithAuthor
|
||||
{
|
||||
use \Winter\Storm\Database\Traits\SoftDelete;
|
||||
}
|
||||
|
||||
class UserWithSoftAuthorAndSoftDelete extends UserWithSoftAuthor
|
||||
{
|
||||
use \Winter\Storm\Database\Traits\SoftDelete;
|
||||
}
|
||||
26
modules/system/tests/fixtures/plugins/database/tester/updates/create_authors_table.php
vendored
Normal file
26
modules/system/tests/fixtures/plugins/database/tester/updates/create_authors_table.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php namespace Database\Tester\Updates;
|
||||
|
||||
use Schema;
|
||||
use Winter\Storm\Database\Updates\Migration;
|
||||
|
||||
class CreateAuthorsTable extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
Schema::create('database_tester_authors', function ($table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->increments('id');
|
||||
$table->integer('user_id')->unsigned()->index()->nullable();
|
||||
$table->integer('country_id')->unsigned()->index()->nullable();
|
||||
$table->string('name')->nullable();
|
||||
$table->string('email')->nullable();
|
||||
$table->softDeletes();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('database_tester_authors');
|
||||
}
|
||||
}
|
||||
46
modules/system/tests/fixtures/plugins/database/tester/updates/create_categories_table.php
vendored
Normal file
46
modules/system/tests/fixtures/plugins/database/tester/updates/create_categories_table.php
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php namespace Database\Tester\Updates;
|
||||
|
||||
use Schema;
|
||||
use Winter\Storm\Database\Updates\Migration;
|
||||
|
||||
class CreateCategoriesTable extends Migration
|
||||
{
|
||||
|
||||
public function up()
|
||||
{
|
||||
Schema::create('database_tester_categories', function ($table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->increments('id');
|
||||
$table->integer('parent_id')->nullable();
|
||||
$table->string('name')->nullable();
|
||||
$table->string('slug')->nullable()->index()->unique();
|
||||
$table->string('description')->nullable();
|
||||
$table->integer('company_id')->unsigned()->nullable();
|
||||
$table->string('language', 3)->nullable();
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
});
|
||||
|
||||
Schema::create('database_tester_categories_nested', function ($table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->increments('id');
|
||||
$table->integer('parent_id')->nullable();
|
||||
$table->integer('nest_left')->nullable();
|
||||
$table->integer('nest_right')->nullable();
|
||||
$table->integer('nest_depth')->nullable();
|
||||
$table->string('name')->nullable();
|
||||
$table->string('slug')->nullable()->index()->unique();
|
||||
$table->string('description')->nullable();
|
||||
$table->integer('company_id')->unsigned()->nullable();
|
||||
$table->string('language', 3)->nullable();
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('database_tester_categories');
|
||||
Schema::dropIfExists('database_tester_categories_nested');
|
||||
}
|
||||
}
|
||||
23
modules/system/tests/fixtures/plugins/database/tester/updates/create_countries_table.php
vendored
Normal file
23
modules/system/tests/fixtures/plugins/database/tester/updates/create_countries_table.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php namespace Database\Tester\Updates;
|
||||
|
||||
use Schema;
|
||||
use Winter\Storm\Database\Updates\Migration;
|
||||
|
||||
class CreateCountriesTable extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
Schema::create('database_tester_countries', function ($table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->increments('id');
|
||||
$table->string('name')->nullable();
|
||||
$table->softDeletes();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('database_tester_countries');
|
||||
}
|
||||
}
|
||||
26
modules/system/tests/fixtures/plugins/database/tester/updates/create_event_log_table.php
vendored
Normal file
26
modules/system/tests/fixtures/plugins/database/tester/updates/create_event_log_table.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php namespace Database\Tester\Updates;
|
||||
|
||||
use Schema;
|
||||
use Winter\Storm\Database\Updates\Migration;
|
||||
|
||||
class CreateEventLogTable extends Migration
|
||||
{
|
||||
|
||||
public function up()
|
||||
{
|
||||
Schema::create('database_tester_event_log', function ($table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->increments('id');
|
||||
$table->string('action', 30)->nullable();
|
||||
$table->string('related_id')->index()->nullable();
|
||||
$table->string('related_type')->index()->nullable();
|
||||
$table->softDeletes();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('database_tester_event_log');
|
||||
}
|
||||
}
|
||||
30
modules/system/tests/fixtures/plugins/database/tester/updates/create_meta_table.php
vendored
Normal file
30
modules/system/tests/fixtures/plugins/database/tester/updates/create_meta_table.php
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php namespace Database\Tester\Updates;
|
||||
|
||||
use Schema;
|
||||
use Winter\Storm\Database\Updates\Migration;
|
||||
|
||||
class CreateMetaTable extends Migration
|
||||
{
|
||||
|
||||
public function up()
|
||||
{
|
||||
Schema::create('database_tester_meta', function ($table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->increments('id')->unsigned();
|
||||
$table->integer('taggable_id')->unsigned()->index()->nullable();
|
||||
$table->string('taggable_type')->nullable();
|
||||
$table->string('meta_title')->nullable();
|
||||
$table->string('meta_description')->nullable();
|
||||
$table->string('meta_keywords')->nullable();
|
||||
$table->string('canonical_url')->nullable();
|
||||
$table->string('redirect_url')->nullable();
|
||||
$table->string('robot_index')->nullable();
|
||||
$table->string('robot_follow')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('database_tester_meta');
|
||||
}
|
||||
}
|
||||
24
modules/system/tests/fixtures/plugins/database/tester/updates/create_phones_table.php
vendored
Normal file
24
modules/system/tests/fixtures/plugins/database/tester/updates/create_phones_table.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php namespace Database\Tester\Updates;
|
||||
|
||||
use Schema;
|
||||
use Winter\Storm\Database\Updates\Migration;
|
||||
|
||||
class CreatePhonesTable extends Migration
|
||||
{
|
||||
|
||||
public function up()
|
||||
{
|
||||
Schema::create('database_tester_phones', function ($table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->increments('id');
|
||||
$table->string('number')->nullable();
|
||||
$table->integer('author_id')->unsigned()->index()->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('database_tester_phones');
|
||||
}
|
||||
}
|
||||
41
modules/system/tests/fixtures/plugins/database/tester/updates/create_posts_table.php
vendored
Normal file
41
modules/system/tests/fixtures/plugins/database/tester/updates/create_posts_table.php
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php namespace Database\Tester\Updates;
|
||||
|
||||
use Schema;
|
||||
use Winter\Storm\Database\Updates\Migration;
|
||||
|
||||
class CreatePostsTable extends Migration
|
||||
{
|
||||
|
||||
public function up()
|
||||
{
|
||||
Schema::create('database_tester_posts', function ($table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->increments('id');
|
||||
$table->string('title')->nullable();
|
||||
$table->string('slug')->nullable()->index();
|
||||
$table->text('long_slug')->nullable();
|
||||
$table->text('description')->nullable();
|
||||
$table->boolean('is_published')->default(false);
|
||||
$table->timestamp('published_at')->nullable();
|
||||
$table->integer('author_id')->unsigned()->index()->nullable();
|
||||
$table->string('author_nickname')->default('Winter')->nullable();
|
||||
$table->softDeletes();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('database_tester_categories_posts', function ($table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->integer('category_id')->unsigned();
|
||||
$table->integer('post_id')->unsigned();
|
||||
$table->primary(['category_id', 'post_id']);
|
||||
$table->string('category_name')->nullable();
|
||||
$table->string('post_name')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('database_tester_categories_posts');
|
||||
Schema::dropIfExists('database_tester_posts');
|
||||
}
|
||||
}
|
||||
34
modules/system/tests/fixtures/plugins/database/tester/updates/create_roles_table.php
vendored
Normal file
34
modules/system/tests/fixtures/plugins/database/tester/updates/create_roles_table.php
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php namespace Database\Tester\Updates;
|
||||
|
||||
use Schema;
|
||||
use Winter\Storm\Database\Updates\Migration;
|
||||
|
||||
class CreateRolesTable extends Migration
|
||||
{
|
||||
|
||||
public function up()
|
||||
{
|
||||
Schema::create('database_tester_roles', function ($table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->increments('id');
|
||||
$table->string('name')->nullable();
|
||||
$table->text('description')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('database_tester_authors_roles', function ($table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->integer('author_id')->unsigned();
|
||||
$table->integer('role_id')->unsigned();
|
||||
$table->primary(['author_id', 'role_id']);
|
||||
$table->string('clearance_level')->nullable();
|
||||
$table->boolean('is_executive')->default(false);
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('database_tester_roles');
|
||||
Schema::dropIfExists('database_tester_authors_roles');
|
||||
}
|
||||
}
|
||||
31
modules/system/tests/fixtures/plugins/database/tester/updates/create_tags_table.php
vendored
Normal file
31
modules/system/tests/fixtures/plugins/database/tester/updates/create_tags_table.php
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php namespace Database\Tester\Updates;
|
||||
|
||||
use Schema;
|
||||
use Winter\Storm\Database\Updates\Migration;
|
||||
|
||||
class CreateTagsTable extends Migration
|
||||
{
|
||||
|
||||
public function up()
|
||||
{
|
||||
Schema::create('database_tester_tags', function ($table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->increments('id');
|
||||
$table->string('name');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('database_tester_taggables', function ($table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->unsignedInteger('tag_id');
|
||||
$table->morphs('taggable', 'testings_taggable');
|
||||
$table->unsignedInteger('added_by')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('database_tester_taggables');
|
||||
Schema::dropIfExists('database_tester_tags');
|
||||
}
|
||||
}
|
||||
25
modules/system/tests/fixtures/plugins/database/tester/updates/create_users_table.php
vendored
Normal file
25
modules/system/tests/fixtures/plugins/database/tester/updates/create_users_table.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php namespace Database\Tester\Updates;
|
||||
|
||||
use Schema;
|
||||
use Winter\Storm\Database\Updates\Migration;
|
||||
|
||||
class CreateUsersTable extends Migration
|
||||
{
|
||||
|
||||
public function up()
|
||||
{
|
||||
Schema::create('database_tester_users', function ($table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->increments('id');
|
||||
$table->string('name')->nullable();
|
||||
$table->string('email')->nullable();
|
||||
$table->softDeletes();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('database_tester_users');
|
||||
}
|
||||
}
|
||||
13
modules/system/tests/fixtures/plugins/database/tester/updates/version.yaml
vendored
Normal file
13
modules/system/tests/fixtures/plugins/database/tester/updates/version.yaml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
1.0.1: First version of Tester
|
||||
1.0.2:
|
||||
- Create tables
|
||||
- create_posts_table.php
|
||||
- create_authors_table.php
|
||||
- create_phones_table.php
|
||||
- create_categories_table.php
|
||||
- create_roles_table.php
|
||||
- create_users_table.php
|
||||
- create_event_log_table.php
|
||||
- create_meta_table.php
|
||||
- create_countries_table.php
|
||||
- create_tags_table.php
|
||||
28
modules/system/tests/fixtures/plugins/dependencytest/acme/Plugin.php
vendored
Normal file
28
modules/system/tests/fixtures/plugins/dependencytest/acme/Plugin.php
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php namespace DependencyTest\Acme;
|
||||
|
||||
use Backend;
|
||||
use Backend\Models\UserRole;
|
||||
use System\Classes\PluginBase;
|
||||
|
||||
/**
|
||||
* Acme Plugin Information File
|
||||
*/
|
||||
class Plugin extends PluginBase
|
||||
{
|
||||
public $require = [
|
||||
'DependencyTest.Dependency',
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns information about this plugin.
|
||||
*/
|
||||
public function pluginDetails(): array
|
||||
{
|
||||
return [
|
||||
'name' => 'ACME',
|
||||
'description' => 'This is a test plugin that will be used to check dependencies are loaded first.',
|
||||
'author' => 'Eric Pfeiffer',
|
||||
'icon' => 'icon-leaf'
|
||||
];
|
||||
}
|
||||
}
|
||||
2
modules/system/tests/fixtures/plugins/dependencytest/acme/updates/version.yaml
vendored
Normal file
2
modules/system/tests/fixtures/plugins/dependencytest/acme/updates/version.yaml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
'1.0.0':
|
||||
- 'First version of Acme'
|
||||
16
modules/system/tests/fixtures/plugins/dependencytest/dependency/Plugin.php
vendored
Normal file
16
modules/system/tests/fixtures/plugins/dependencytest/dependency/Plugin.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php namespace DependencyTest\Dependency;
|
||||
|
||||
use System\Classes\PluginBase;
|
||||
|
||||
class Plugin extends PluginBase
|
||||
{
|
||||
public function pluginDetails()
|
||||
{
|
||||
return [
|
||||
'name' => 'Dependency Test - Dependency',
|
||||
'description' => 'This is a test plugin that will act as a dependency for the other test plugins in this
|
||||
namespace.',
|
||||
'author' => 'Ben Thomson'
|
||||
];
|
||||
}
|
||||
}
|
||||
1
modules/system/tests/fixtures/plugins/dependencytest/dependency/updates/version.yaml
vendored
Normal file
1
modules/system/tests/fixtures/plugins/dependencytest/dependency/updates/version.yaml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
1.0.1: Initial version of the plugin
|
||||
19
modules/system/tests/fixtures/plugins/dependencytest/found/Plugin.php
vendored
Normal file
19
modules/system/tests/fixtures/plugins/dependencytest/found/Plugin.php
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php namespace DependencyTest\Found;
|
||||
|
||||
use System\Classes\PluginBase;
|
||||
|
||||
class Plugin extends PluginBase
|
||||
{
|
||||
public $require = [
|
||||
'DependencyTest.Dependency'
|
||||
];
|
||||
|
||||
public function pluginDetails()
|
||||
{
|
||||
return [
|
||||
'name' => 'Dependency Test - Found',
|
||||
'description' => 'This is a test plugin with a dependency that exists.',
|
||||
'author' => 'Ben Thomson'
|
||||
];
|
||||
}
|
||||
}
|
||||
1
modules/system/tests/fixtures/plugins/dependencytest/found/updates/version.yaml
vendored
Normal file
1
modules/system/tests/fixtures/plugins/dependencytest/found/updates/version.yaml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
1.0.1: Initial version of the plugin
|
||||
19
modules/system/tests/fixtures/plugins/dependencytest/notfound/Plugin.php
vendored
Normal file
19
modules/system/tests/fixtures/plugins/dependencytest/notfound/Plugin.php
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php namespace DependencyTest\NotFound;
|
||||
|
||||
use System\Classes\PluginBase;
|
||||
|
||||
class Plugin extends PluginBase
|
||||
{
|
||||
public $require = [
|
||||
'DependencyTest.Missing'
|
||||
];
|
||||
|
||||
public function pluginDetails()
|
||||
{
|
||||
return [
|
||||
'name' => 'Dependency Test - Not Found',
|
||||
'description' => 'This is a test plugin with a dependency that does not exist.',
|
||||
'author' => 'Ben Thomson'
|
||||
];
|
||||
}
|
||||
}
|
||||
1
modules/system/tests/fixtures/plugins/dependencytest/notfound/updates/version.yaml
vendored
Normal file
1
modules/system/tests/fixtures/plugins/dependencytest/notfound/updates/version.yaml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
1.0.1: Initial version of the plugin
|
||||
19
modules/system/tests/fixtures/plugins/dependencytest/wrongcase/Plugin.php
vendored
Normal file
19
modules/system/tests/fixtures/plugins/dependencytest/wrongcase/Plugin.php
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php namespace DependencyTest\WrongCase;
|
||||
|
||||
use System\Classes\PluginBase;
|
||||
|
||||
class Plugin extends PluginBase
|
||||
{
|
||||
public $require = [
|
||||
'Dependencytest.dependency'
|
||||
];
|
||||
|
||||
public function pluginDetails()
|
||||
{
|
||||
return [
|
||||
'name' => 'Dependency Test - Wrong Case',
|
||||
'description' => 'This is a test plugin with a dependency that exists, but is using the wrong letter case.',
|
||||
'author' => 'Ben Thomson'
|
||||
];
|
||||
}
|
||||
}
|
||||
1
modules/system/tests/fixtures/plugins/dependencytest/wrongcase/updates/version.yaml
vendored
Normal file
1
modules/system/tests/fixtures/plugins/dependencytest/wrongcase/updates/version.yaml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
1.0.1: Initial version of the plugin
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user