jqh vor 5 Jahren
Ursprung
Commit
4f2605f8c7

+ 1 - 0
src/Admin.php

@@ -242,6 +242,7 @@ class Admin
         app('router')->group($attributes, function ($router) {
         app('router')->group($attributes, function ($router) {
             /* @var \Illuminate\Routing\Router $router */
             /* @var \Illuminate\Routing\Router $router */
             $router->namespace('Dcat\Admin\Controllers')->group(function ($router) {
             $router->namespace('Dcat\Admin\Controllers')->group(function ($router) {
+                /* @var \Illuminate\Routing\Router $router */
                 $router->post('action', 'HandleActionController@handle')->name('action');
                 $router->post('action', 'HandleActionController@handle')->name('action');
                 $router->post('form', 'HandleFormController@handle')->name('form');
                 $router->post('form', 'HandleFormController@handle')->name('form');
                 $router->post('value', 'ValueController@handle')->name('value');
                 $router->post('value', 'ValueController@handle')->name('value');

+ 5 - 5
src/Grid/Concerns/HasNames.php

@@ -14,7 +14,7 @@ trait HasNames
      *
      *
      * @var string
      * @var string
      */
      */
-    protected $__name;
+    protected $_name;
 
 
     /**
     /**
      * HTML element names.
      * HTML element names.
@@ -37,7 +37,7 @@ trait HasNames
      */
      */
     public function setName($name)
     public function setName($name)
     {
     {
-        $this->__name = $name;
+        $this->_name = $name;
         $this->tableId = $this->tableId.'-'.$name;
         $this->tableId = $this->tableId.'-'.$name;
 
 
         $model = $this->model();
         $model = $this->model();
@@ -60,7 +60,7 @@ trait HasNames
      */
      */
     public function getName()
     public function getName()
     {
     {
-        return $this->__name;
+        return $this->_name;
     }
     }
 
 
     /**
     /**
@@ -102,8 +102,8 @@ trait HasNames
     {
     {
         $elementName = $this->elementNames[$name];
         $elementName = $this->elementNames[$name];
 
 
-        if ($this->__name) {
-            return sprintf('%s-%s', $this->__name, $elementName);
+        if ($this->_name) {
+            return sprintf('%s-%s', $this->_name, $elementName);
         }
         }
 
 
         return $elementName;
         return $elementName;

+ 2 - 0
tests/Browser/AuthTest.php

@@ -6,6 +6,8 @@ use Laravel\Dusk\Browser;
 use Tests\TestCase;
 use Tests\TestCase;
 
 
 /**
 /**
+ * 鉴权登陆功能测试.
+ *
  * @group auth
  * @group auth
  */
  */
 class AuthTest extends TestCase
 class AuthTest extends TestCase

+ 3 - 3
tests/Browser/Components/Component.php

@@ -14,7 +14,7 @@ abstract class Component extends BaseComponent
      */
      */
     public function parentSelector(Browser $browser)
     public function parentSelector(Browser $browser)
     {
     {
-        return str_replace($this->selector(), '', $browser->resolver->prefix);
+        return $browser->resolver->prefix;
     }
     }
 
 
     /**
     /**
@@ -25,8 +25,8 @@ abstract class Component extends BaseComponent
      *
      *
      * @return string
      * @return string
      */
      */
-    public function formatSelector(Browser $browser, $selector = null)
+    public function formatSelector(Browser $browser, $selector = '')
     {
     {
-        return $this->parentSelector($browser).' '.($selector ?: $this->selector());
+        return $browser->resolver->format($selector);
     }
     }
 }
 }

+ 3 - 3
tests/Browser/Components/Form/Field/Tree.php

@@ -21,7 +21,7 @@ class Tree extends Component
      */
      */
     public function selector()
     public function selector()
     {
     {
-        return ".{$this->name}-tree-wrapper";
+        return '@container';
     }
     }
 
 
     /**
     /**
@@ -45,8 +45,8 @@ class Tree extends Component
     public function elements()
     public function elements()
     {
     {
         return [
         return [
-            '@container' => $this->selector(),
-            '@tree'      => "{$this->selector()} .da-tree",
+            '@container' => ".{$this->name}-tree-wrapper",
+            '@tree'      => '.da-tree',
             '@input'     => sprintf('input[name="%s"][type="hidden"]', $this->name),
             '@input'     => sprintf('input[name="%s"][type="hidden"]', $this->name),
         ];
         ];
     }
     }

+ 1 - 1
tests/Browser/Components/Form/MenuCreationForm.php

@@ -24,7 +24,7 @@ class MenuCreationForm extends Component
      */
      */
     public function selector()
     public function selector()
     {
     {
-        return $this->selector;
+        return '@form';
     }
     }
 
 
     /**
     /**

+ 87 - 0
tests/Browser/Components/Grid/Actions/Delete.php

@@ -0,0 +1,87 @@
+<?php
+
+namespace Tests\Browser\Components\Grid;
+
+use Laravel\Dusk\Browser;
+use Tests\Browser\Components\Component;
+
+/**
+ * 行选择器.
+ */
+class Delete extends Component
+{
+    /**
+     * 获取组件的 root selector
+     *
+     * @return string
+     */
+    public function selector()
+    {
+        return '@item';
+    }
+
+    /**
+     * 浏览器包含组件的断言
+     *
+     * @param  Browser  $browser
+     * @return void
+     */
+    public function assert(Browser $browser)
+    {
+        $browser->assertVisible('table thead th .checkbox-grid');
+    }
+
+    /**
+     * 读取组件的元素快捷方式
+     *
+     * @return array
+     */
+    public function elements()
+    {
+        return [
+            '@all' => 'input.select-all',
+            '@item' => 'input.grid-row-checkbox',
+        ];
+    }
+
+    /**
+     * 选中.
+     *
+     * @param  Browser       $browser
+     * @param  string|array  $value
+     *
+     * @return Browser
+     */
+    public function choose(Browser $browser, $value)
+    {
+        foreach ((array) $value as $v) {
+            $browser->script(
+                <<<JS
+setTimeout(function () {
+    $('{$this->formatSelector($browser)}[data-id="{$v}"]').prop('checked', true);
+}, 10)
+JS
+            );
+        }
+
+        return $browser;
+    }
+
+    /**
+     * 选中所有
+     *
+     * @param Browser $browser
+     *
+     * @return Browser
+     */
+    public function selectAll(Browser $browser)
+    {
+        $browser->script("Dcat.ready(
+            setTimeout(function () {
+                $('.grid-select-all').first().click()
+            }, 10)
+        );");
+
+        return $browser;
+    }
+}

+ 139 - 0
tests/Browser/Components/Grid/BatchActions.php

@@ -0,0 +1,139 @@
+<?php
+
+namespace Tests\Browser\Components\Grid;
+
+use Laravel\Dusk\Browser;
+use Tests\Browser\Components\Component;
+
+/**
+ * 批量操作.
+ */
+class BatchActions extends Component
+{
+    protected $gridName;
+
+    protected $prefix;
+
+    public function __construct($gridName = '')
+    {
+        $this->gridName = $gridName;
+        $this->prefix = $gridName ? $gridName.'-' : '';
+    }
+
+    /**
+     * 获取组件的 root selector
+     *
+     * @return string
+     */
+    public function selector()
+    {
+        return '@container';
+    }
+
+    /**
+     * 浏览器包含组件的断言
+     *
+     * @param  Browser  $browser
+     * @return void
+     */
+    public function assert(Browser $browser)
+    {
+    }
+
+    /**
+     * 读取组件的元素快捷方式
+     *
+     * @return array
+     */
+    public function elements()
+    {
+        $container = ".{$this->prefix}grid-select-all-btn";
+
+        return [
+            '@container' => $container,
+            '@btn' => '.btn',
+            '@menu' => '.dropdown-menu',
+            '@item' => '.dropdown-menu .dropdown-item',
+        ];
+    }
+
+    /**
+     * 判断按钮是否已显示.
+     *
+     * @param Browser $browser
+     * @param null $number
+     *
+     * @return Browser
+     */
+    public function shown(Browser $browser, $number = null)
+    {
+        if ($number) {
+            $browser->waitForText(str_replace('{n}', $number, __('admin.grid_items_selected')), 1);
+        }
+
+        $browser->whenElementAvailable('@btn', 1);
+
+        return $browser;
+    }
+
+    /**
+     * 显示菜单.
+     *
+     * @param Browser $browser
+     * @param int     $seconds
+     *
+     * @return Browser
+     */
+    public function open(Browser $browser)
+    {
+        $this->shown($browser);
+
+        $browser->script(
+            <<<JS
+$('{$this->formatSelector($browser)}').addClass('show');
+JS
+        );
+
+        $browser->whenElementAvailable('@menu', 1);
+
+        return $browser;
+    }
+
+    /**
+     * 关闭菜单.
+     *
+     * @param Browser $browser
+     * @param int     $seconds
+     *
+     * @return Browser
+     */
+    public function close(Browser $browser)
+    {
+        $this->shown($browser);
+
+        $browser->script(
+            <<<JS
+$('{$this->formatSelector($browser)}').removeClass('show');
+JS
+        );
+
+        return $browser;
+    }
+
+    /**
+     * 点击选项.
+     *
+     * @param  Browser $browser
+     * @param  string  $value
+     *
+     * @return Browser
+     */
+    public function choose(Browser $browser, $value)
+    {
+        $browser->with('@menu', function (Browser $browser) use ($value) {
+            $browser->clickLink($value);
+        });
+
+        return $browser;
+    }
+}

+ 87 - 0
tests/Browser/Components/Grid/RowSelector.php

@@ -0,0 +1,87 @@
+<?php
+
+namespace Tests\Browser\Components\Grid;
+
+use Laravel\Dusk\Browser;
+use Tests\Browser\Components\Component;
+
+/**
+ * 行选择器.
+ */
+class RowSelector extends Component
+{
+    /**
+     * 获取组件的 root selector
+     *
+     * @return string
+     */
+    public function selector()
+    {
+        return '@item';
+    }
+
+    /**
+     * 浏览器包含组件的断言
+     *
+     * @param  Browser  $browser
+     * @return void
+     */
+    public function assert(Browser $browser)
+    {
+        $browser->assertVisible('table thead th .checkbox-grid');
+    }
+
+    /**
+     * 读取组件的元素快捷方式
+     *
+     * @return array
+     */
+    public function elements()
+    {
+        return [
+            '@all' => 'input.select-all',
+            '@item' => 'input.grid-row-checkbox',
+        ];
+    }
+
+    /**
+     * 选中.
+     *
+     * @param  Browser       $browser
+     * @param  string|array  $value
+     *
+     * @return Browser
+     */
+    public function choose(Browser $browser, $value)
+    {
+        foreach ((array) $value as $v) {
+            $browser->script(
+                <<<JS
+setTimeout(function () {
+    $('{$this->formatSelector($browser)}[data-id="{$v}"]').prop('checked', true);
+}, 10)
+JS
+            );
+        }
+
+        return $browser;
+    }
+
+    /**
+     * 选中所有
+     *
+     * @param Browser $browser
+     *
+     * @return Browser
+     */
+    public function selectAll(Browser $browser)
+    {
+        $browser->script("Dcat.ready(
+            setTimeout(function () {
+                $('.grid-select-all').first().click()
+            }, 10)
+        );");
+
+        return $browser;
+    }
+}

+ 3 - 1
tests/Browser/InstallTest.php → tests/Browser/Feature/InstallTest.php

@@ -1,11 +1,13 @@
 <?php
 <?php
 
 
-namespace Tests\Browser;
+namespace Tests\Browser\Feature;
 
 
 use Dcat\Admin\Admin;
 use Dcat\Admin\Admin;
 use Tests\TestCase;
 use Tests\TestCase;
 
 
 /**
 /**
+ * 安装功能测试.
+ *
  * @group install
  * @group install
  */
  */
 class InstallTest extends TestCase
 class InstallTest extends TestCase

+ 112 - 0
tests/Browser/Feature/SectionTest.php

@@ -0,0 +1,112 @@
+<?php
+
+namespace Tests\Browser\Feature;
+
+use Tests\TestCase;
+
+/**
+ * Section功能测试.
+ *
+ * @group section
+ */
+class SectionTest extends TestCase
+{
+    protected $login = false;
+
+    public function testInjectValues()
+    {
+        // view
+        admin_inject_section('key1', view('admin-tests::test'));
+
+        $this->assertSame(admin_section('key1'), '<h1>Hello world</h1>');
+
+        // string
+        admin_inject_section('key2', 'test');
+
+        $this->assertSame(admin_section('key2'), 'test');
+
+        // callable
+        admin_inject_section('key3', function () {
+            return view('admin-tests::test');
+        });
+
+        $this->assertSame(admin_section('key3'), '<h1>Hello world</h1>');
+    }
+
+    public function testOptions()
+    {
+        admin_inject_section('key1', 'value1');
+
+        admin_inject_section('key1', function ($options) {
+            return "previous:{$options->previous},name:{$options->name},age:{$options->age}";
+        }, false);
+
+        $this->assertSame(
+            admin_section('key1', null, ['name' => 'Mike', 'age' => 18]),
+            'previous:value1,name:Mike,age:18'
+        );
+    }
+
+    public function testAppend()
+    {
+        // 1 append
+        admin_inject_section('key1', 'test1,');
+        admin_inject_section('key1', 'test2,');
+        admin_inject_section('key1', 'test3,');
+
+        $this->assertSame(admin_section('key1'), 'test1,test2,test3,');
+
+        // 2 overwrite
+        admin_inject_section('key2', 'test1,');
+        admin_inject_section('key2', 'test2,', false);
+
+        $this->assertSame(admin_section('key2'), 'test2,');
+
+        admin_inject_section('key2', 'test3,', false);
+
+        $this->assertSame(admin_section('key2'), 'test3,');
+
+        // 3 overwrite
+        admin_inject_section('key3', 'test1,');
+        admin_inject_section('key3', 'test2,', false);
+        admin_inject_section('key3', function ($options) {
+            return $options->previous.'test3,';
+        }, false);
+        admin_inject_section('key3', function ($options) {
+            return $options->previous.'test4,';
+        }, false);
+
+        $this->assertSame(admin_section('key3'), 'test2,test3,test4,');
+    }
+
+    public function testSort()
+    {
+        // 值越大排序越靠前
+        admin_inject_section('key1', '4,', true, -100);
+        admin_inject_section('key1', '2,', true, 2);
+        admin_inject_section('key1', '1,', true, 3);
+        admin_inject_section('key1', '3,', true, 1);
+
+        $this->assertSame(admin_section('key1'), '1,2,3,4,');
+    }
+
+    public function testInjectDefaultSection()
+    {
+        // step1
+        admin_inject_default_section('key', 'Hello');
+
+        $this->assertSame(admin_section('key'), 'Hello');
+
+        // step2
+        admin_inject_default_section('key', function ($options) {
+            return 'Hello '.$options->var1;
+        });
+
+        $this->assertSame(admin_section('key', null, ['var1' => 'world']), 'Hello world');
+
+        // step3
+        admin_inject_section('key', '');
+
+        $this->assertSame(admin_section('key'), '');
+    }
+}

+ 2 - 0
tests/Browser/IndexTest.php

@@ -6,6 +6,8 @@ use Laravel\Dusk\Browser;
 use Tests\TestCase;
 use Tests\TestCase;
 
 
 /**
 /**
+ * 首页功能测试.
+ *
  * @group index
  * @group index
  */
  */
 class IndexTest extends TestCase
 class IndexTest extends TestCase

+ 2 - 0
tests/Browser/MenuTest.php

@@ -12,6 +12,8 @@ use Tests\Browser\Pages\MenuPage;
 use Tests\TestCase;
 use Tests\TestCase;
 
 
 /**
 /**
+ * 菜单管理功能测试.
+ *
  * @group menu
  * @group menu
  */
  */
 class MenuTest extends TestCase
 class MenuTest extends TestCase

+ 131 - 0
tests/Browser/OperationLogTest.php

@@ -0,0 +1,131 @@
+<?php
+
+namespace Tests\Browser;
+
+use Dcat\Admin\Models\OperationLog;
+use Laravel\Dusk\Browser;
+use Tests\Browser\Components\Grid\BatchActions;
+use Tests\Browser\Components\Grid\RowSelector;
+use Tests\TestCase;
+
+/**
+ * 操作日志功能测试.
+ *
+ * @group log
+ */
+class OperationLogTest extends TestCase
+{
+    public function testOperationLogIndex()
+    {
+        $this->browse(function (Browser $browser) {
+            $browser->visit(test_admin_path('auth/menu'))
+                ->assertPathIs(test_admin_path('auth/menu'))
+                ->visit(test_admin_path('auth/logs'))
+                ->assertSee(__('admin.operation_log'))
+                ->assertSee(__('admin.list'))
+                ->assertSee(__('admin.refresh'))
+                ->assertSee(__('admin.filter'))
+                ->assertSee('ID')
+                ->assertSee(__('admin.user'))
+                ->assertSee(__('admin.method'))
+                ->assertSee(__('admin.uri'))
+                ->assertSee('IP')
+                ->assertSee(__('admin.input'))
+                ->assertSee(__('admin.created_at'))
+                ->assertSee(__('admin.action'))
+                ->waitForText(__('admin.responsive.display'), 2)
+                ->assertSee(__('admin.responsive.display_all'));
+        });
+    }
+
+    public function testGenerateLogs()
+    {
+        $this->browse(function (Browser $browser) {
+            $table = config('admin.database.operation_log_table');
+
+            $browser->visit(test_admin_path('auth/menu'))
+                ->assertPathIs(test_admin_path('auth/menu'))
+                ->visit(test_admin_path('auth/users'))
+                ->assertPathIs(test_admin_path('auth/users'))
+                ->visit(test_admin_path('auth/permissions'))
+                ->assertPathIs(test_admin_path('auth/permissions'))
+                ->visit(test_admin_path('auth/roles'))
+                ->assertPathIs(test_admin_path('auth/roles'))
+                ->visit(test_admin_path('auth/logs'))
+                ->assertPathIs(test_admin_path('auth/logs'));
+
+            $this->seeInDatabase($table, ['path' => trim(test_admin_path('auth/menu'), '/'), 'method' => 'GET'])
+                ->seeInDatabase($table, ['path' => trim(test_admin_path('auth/users'), '/'), 'method' => 'GET'])
+                ->seeInDatabase($table, ['path' => trim(test_admin_path('auth/permissions'), '/'), 'method' => 'GET'])
+                ->seeInDatabase($table, ['path' => trim(test_admin_path('auth/roles'), '/'), 'method' => 'GET']);
+        });
+
+        $this->assertSame(4, OperationLog::count());
+    }
+
+    public function testDeleteLogs()
+    {
+        $this->browse(function (Browser $browser) {
+            $table = config('admin.database.operation_log_table');
+
+            $this->assertEquals(0, OperationLog::count());
+
+            $browser->visit(test_admin_path('auth/users'));
+            $this->seeInDatabase($table, ['path' => trim(test_admin_path('auth/users'), '/'), 'method' => 'GET']);
+
+            $browser->visit(test_admin_path('auth/logs'))
+                ->assertPathIs(test_admin_path('auth/logs'))
+                ->pause(500);
+
+            $browser->script("$('a[data-action=delete]').first().click()");
+            $browser->waitForText(__('admin.delete_confirm'), 3);
+            $browser->script("$('.swal2-confirm').first().click()");
+            $browser->waitForText(__('admin.delete_succeeded'), 3);
+
+            $this->assertEquals(0, OperationLog::count());
+        });
+    }
+
+    public function testDeleteMultipleLogs()
+    {
+        $this->browse(function (Browser $browser) {
+            $table = config('admin.database.operation_log_table');
+
+            $browser->visit(test_admin_path('auth/menu'))
+                ->visit(test_admin_path('auth/users'))
+                ->visit(test_admin_path('auth/permissions'))
+                ->visit(test_admin_path('auth/roles'));
+
+            $number = 4;
+
+            $this->seeInDatabase($table, ['path' => trim(test_admin_path('auth/menu'), '/'), 'method' => 'GET'])
+                ->seeInDatabase($table, ['path' => trim(test_admin_path('auth/users'), '/'), 'method' => 'GET'])
+                ->seeInDatabase($table, ['path' => trim(test_admin_path('auth/permissions'), '/'), 'method' => 'GET'])
+                ->seeInDatabase($table, ['path' => trim(test_admin_path('auth/roles'), '/'), 'method' => 'GET'])
+                ->assertEquals($number, OperationLog::count());
+
+            $browser->visit(test_admin_path('auth/logs'))
+                ->assertPathIs(test_admin_path('auth/logs'));
+
+            $browser->with(new RowSelector(), function (Browser $browser) {
+                $browser->selectAll();
+            });
+
+            $browser->with(new BatchActions(), function (Browser $browser) use ($number) {
+                $browser->shown($number);
+                $browser->open();
+                $browser->choose(__('admin.delete'));
+            });
+
+//            $browser->waitForText(__('admin.delete_confirm'), 3);
+//            $browser->script("$('.swal2-confirm').first().click()");
+//            $browser->waitForText(__('admin.delete_succeeded'), 3);
+//
+//            $this->notSeeInDatabase($table, ['path' => trim(test_admin_path('auth/menu'), '/'), 'method' => 'GET'])
+//                ->notSeeInDatabase($table, ['path' => trim(test_admin_path('auth/users'), '/'), 'method' => 'GET'])
+//                ->notSeeInDatabase($table, ['path' => trim(test_admin_path('auth/permissions'), '/'), 'method' => 'GET'])
+//                ->notSeeInDatabase($table, ['path' => trim(test_admin_path('auth/roles'), '/'), 'method' => 'GET'])
+//                ->assertEquals(0, OperationLog::count());
+        });
+    }
+}

+ 2 - 2
tests/BrowserExtension.php

@@ -19,7 +19,7 @@ trait BrowserExtension
 
 
                 if (is_callable($callbackOrSeconds)) {
                 if (is_callable($callbackOrSeconds)) {
                     $callback = $callbackOrSeconds;
                     $callback = $callbackOrSeconds;
-                } elseif (is_int($callbackOrSeconds)) {
+                } elseif (is_numeric($callbackOrSeconds)) {
                     $seconds = $callbackOrSeconds;
                     $seconds = $callbackOrSeconds;
                 }
                 }
 
 
@@ -41,7 +41,7 @@ trait BrowserExtension
                 $callback = null;
                 $callback = null;
                 if (is_callable($callbackOrSeconds)) {
                 if (is_callable($callbackOrSeconds)) {
                     $callback = $callbackOrSeconds;
                     $callback = $callbackOrSeconds;
-                } elseif (is_int($callbackOrSeconds)) {
+                } elseif (is_numeric($callbackOrSeconds)) {
                     $seconds = $callbackOrSeconds;
                     $seconds = $callbackOrSeconds;
                 }
                 }