I'm contributing to a package that will provide some blade components. So, the users of this package may use the components on a blade template as:
<x-mypackage-component-a/>
The components are located under the src/Components folder of my package. These components are loaded in the package service provider using the loadViewComponentsAs() method as explained here:
$this->loadViewComponentsAs('mypackage', [
Components\ComponentA::class,
...
]);
Now, I need to make some tests for phpunit that should check that the components are loaded by the package service provider, something like next:
public function testComponentsAreLoaded()
{
$this->assertTrue(/*code that check 'x-mypackage-component-a' exists*/);
}
Is there any way (using the Laravel framework) to check a blade component name exists and/or is loaded?
I have manage to do something similar for a set of blade views provided by the package with next code:
// Views are loaded on the package service provider as:
$this->loadViewsFrom($viewsPath, 'mypackage');
// The phpunit test method is:
public function testViewsAreLoaded()
{
$this->assertTrue(View::exists('mypackage::view-a'));
$this->assertTrue(View::exists('mypackage::view-b'));
...
}
Thanks in advance!
Finally managed to find a way to solve this, I'm going to explain this because it may be useful for other readers. First, you need to load the set of views that are used by the component classes (the ones you usually use on the render() method). In my particular case the component views are located on the resources/components folder, so I had to insert next code on the boot() method of my package's service provider:
// Load the blade views used by the components.
$viewsPath = $this->packagePath('resources/components');
$this->loadViewsFrom($viewsPath, 'mypackage');
Where packagePath() is a method that returns the fully qualified path (from the package root folder) to the received argument.
Next, again in the boot() method, I had to load the components as explained on the question:
$this->loadViewComponentsAs('mypackage', [
Components\ComponentA::class,
Components\ComponentB::class,
...
]);
Finally, in order to make a test that asserts the views and the components are loaded correctly by the service provider, I have created the next method to be used with phpunit:
public function testComponentsAreLoaded()
{
// Check that the blade component views are loaded.
$this->assertTrue(View::exists('mypackage::component-a'));
$this->assertTrue(View::exists('mypackage::component-b'));
...
// Now, check that the class components aliases are registered.
$aliases = Blade::getClassComponentAliases();
$this->assertTrue(isset($aliases['mypackage-component-a']));
$this->assertTrue(isset($aliases['mypackage-component-b']));
...
}
As an additional information, I must say that my phpunit test classes inherits from Orchestral/testbench TestCase class, and you may need to include the View and Blade facades on your test file. I'm also using the next method to ensure the boot() method of my package's service provider executes on my test environment before running the tests:
protected function getPackageProviders($app)
{
return ['Namespace\To\MyPackageServiceProvider'];
}
there is no method or helper for checking that a component exists or not but from then blade components are class in laravel, so you can check that your specific component class exists or not:
// application namespaces
namespace App\View\Components;
use Illuminate\View\Component;
// define component
class mypackage extends Component { ... }
// check component
public function testViewsAreLoaded(){
$this->assertTrue(class_exists('\Illuminate\View\Component\mypackage'));
...
}
Related
I'm trying to do tdd with my WordPress plugins. The problem is that using WP_UnitTestCase is way way to slow and despite the name provides integration tests rather than unit tests. So instead of using WP_UnitTestCase I have been working on creating truly isolated tests for my plugins but the problem is that I find myself using a lot of WordPress global functions such as wp_get_current_user() or wp_signon().
Currently I have a file of the functions I've used that are basically stubbed out.
What is the best way to go about mocking these functions? Ultimately I'd like to be able to mock these functions the same way as I would other methods with the ability to control their output and test that they're called. Is there a more OO way to set the current user or check for authentication that I'm missing?
You can create a class for invoking global WordPress functions. This can have a map of methods to global functions or even invoking whatever method is called that starts with wp_ using __call or any other way you come up with.
Then you would use this class from inside your plugin to call the functions. I suppose plugins are instantiated by WordPress so you won't be able to inject this class on production code. So you can make it externally settable to allow injecting a mock but if none is provided, use the real one.
Like this:
<?php
class Plugin
{
private $invoker;
public function getWpInvoker()
{
if (!isset($this->invoker)) {
$this->invoker = new WordPressGlobalFunctionsInvoker();
}
}
public function setWpInvoker(WordPressGlobalFunctionsInvoker $invoker)
{
$this->wp_invoker = $invoker;
}
public function foo()
{
$current_user = $this->getWpInvoker()->wp_get_current_user();
}
}
In the test you would mock the WordPressGlobalFunctionsInvoker class and inject the mock to the plugin so you take control over the functions being called.
I have a package checking function that needs to check if the logged in user has a valid package. This functionality is identical across all modules but is not needed in every module action.
protected function checkPackage()
{
if($this->MscdbProject->getCurrentPackage()){
return;
}
$this->getUser()->setFlash('error',"Your package has expired, to restore access to your project please contact us to renew it.");
$this->redirect('project/index');
}
I need to access this function in most module actions across multiple modules but it relies on the MscdbProject variable which is pulled in the individual actions, this is sllightly different in different modules so cannot be standardised.
Currently I have this function duplicated in every module and I call it from every action where it is needed.
How can I refactor this to avoid this duplication?
It feels like a filter should be able to do this but I have to have pulled the MscdbProject instance before I can check the package status.
Thanks
Change the base class for your action classes to your own:
class myAction extends sfAction {
abstract protected function getMscdbProject();
protected function checkPackage()
{
if($this->getMscdbProject()->getCurrentPackage()){
return;
}
$this->getUser()->setFlash('error',"Your package has expired, to restore access to your project please contact us to renew it.");
$this->redirect('project/index');
}
}
Now your module action have to implement getMscdbProject() using their own logic.
If you are using generated modules, change this key in generator.yml:
generator:
param:
actions_base_class: myAction
Is there a way to override the controller file located at /concrete/blocks/page_list/controller.php and place it inside /packages/mypackage/blocks/page_list/? I'd like to make some changes to the original edit and view.
In /packages/mypackage/blocks/page_list/controller.php, I tried doing this but it does not seem to have any effect:
class PageListBlockController extends Concrete5_Controller_Block_PageList { ... }
You can now override/extend core classes via packages in newer versions Concrete5 (v.5.6+).
You must add to your package's main controller.php file:
public function on_start(){
$objEnv = Environment::get();
$objEnv->overrideCoreByPackage('blocks/page_list/controller.php', $this);
}
You don't have to copy over the whole core controller, just declare your new block controller like this:
class PageList extends Concrete5_Controller_Block_Page_List {
public function mymethod() {
}
}
(what class you're extending and where you put the file may vary depending on your C5 version - just compare the /concrete/ folder structure and files for reference)
The following C5 forum posts may be of help:
Overriding Core Class with Package
Can A Package Override A Core Library?
A caution, though - if you're hoping to submit to the official C5 marketplace, they generally don't accept Add-Ons with overrides.
No. You can't override a block controller from within a package. Just imagine if more than one package did this. (You can, however, have a block template within your package directory, but this makes sense because it adds rather than replaces.)
If you can, you should override by putting it in /blocks/page_list/controller.php.
However, if you still need to override it from you package, you should look into the not-very-well-supported Environment::overrideCoreByPackage() and try:
Environment::get()->overrideCoreByPackage('/blocks/page_list/controller.php', $myPackage);
See the source:
https://github.com/concrete5/concrete5/blob/master/web/concrete/core/libraries/environment.php#L123
And an example of usage:
http://www.concrete5.org/community/forums/customizing_c5/override-a-core-class-within-a-package/#460765
My main application contains a ClassA. The main application then loads a module and in that module I would like would to do:
var classA:InterfaceClassA = new ClassA();
It compiles fine but I get this warning:
Warning: YourApplication is a module or application that is directly referenced. This will cause YourApplication and all of its dependencies to be linked in with module.YourModule:Module. Using an interface is the recommended practice to avoid this.
I can't use an interface to generate the new instance, so what is the correct way to do this?
I found an answer in Accessing the parent application from the modules . I created a helper class in the main Application that contains instances of the classes I want to access. In the module I then use:
parentApplication.myModuleHelper.**myClassInstance**.myMethod();
for instance methods and for static class level methods I use:
parentApplication.myModuleHelper.**MyClassInstance**.myMethod()
To get an instance of my class in a module I use this in MyModuleHelper
public function getFullScreenUtil(iFullScreenUtil:IFullScreenUtil , iSystemManager:ISystemManager):FullScreenUtil {
return new FullScreenUtil(iFullScreenUtil , iSystemManager);
}
and this in MyModule:
var _fullScreenUtil:* = parentApplication.moduleHelper.getFullScreenUtil(this , systemManager);
which is all I need for now. I am not sure how I could cast the result of getFullScreenUtil(..) to an actual instance of FullScreenUtil but I expect that it can not be done in modules. Maybe using an interface would provide the solution to that.
I have a trivially small PHPUnit test that looks like this:
<?php
namespace VNN\PressboxBundle\Tests\Entity;
namespace VNN\PressboxBundle\Entity;
use VNN\PressboxBundle\Entity\User;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Phactory\Sql\Phactory;
class UserTest extends EntityTest
{
public function testCreate()
{
Phactory::reset();
}
}
When I try to run it, I get this:
There was 1 error:
1) VNN\PressboxBundle\Entity\UserTest::testCreate
ErrorException: Runtime Notice: Non-static method Phactory\Sql\Phactory::reset() should not be called statically, assuming $this from incompatible context in /Users/jason/Web/pressbox/src/VNN/PressboxBundle/Tests/Entity/UserTest.php line 13
What's up with that? All the docs call it statically.
I'm doing this on Symfony 2.0, if that makes a difference.
The documentation says you should be using the top-level Phactory class directly under lib/--not the individual implementations such as Phactory/Sql/Phactory which get instantiated based on the PDO object you pass to setConnection. Change
use Phactory\Sql\Phactory;
to
require_once 'Phactory/lib/Phactory.php';
The main class is in the global namespace and doesn't require a use statement.
https://github.com/chriskite/phactory/issues/30
From the code, setConnection, define and create are not static functions but the README and website guide do not reflect that.
e.g. test code
https://github.com/chriskite/phactory/blob/next/tests/Phactory/Sql/PhactoryTest.php
use Phactory\Sql\Phactory;
...
$this->pdo = new \PDO("sqlite:test.db");
$this->phactory = new Phactory($this->pdo);
$this->phactory->define('user');
$this->phactory->reset();
I don't know when it has been changed.
Too late anyways...
The current version, 0.3.2, is not backward compatible with the static method structure that is documented.
Here is the breaking commit: https://github.com/chriskite/phactory/commit/d3b60eeedea955ab7b5803ec29446d19888d3849
Unfortunately, the documentation has not been updated on http://phactory.org and the pearhub repo is no longer available.
I would look to the tests for examples: https://github.com/chriskite/phactory/blob/next/tests/Phactory/Sql/PhactoryTest.php