jaro

AutoExportTemplatesAndFields enables continuous integration of template and field configuration changes

Recommended Posts

Hello,

in one of my current projects, we have a test and production stage with their own ProcessWire installations, and we regularly want to migrate template/field configuration to the next stage without migrating content as well. ProcessWire supports this via the import/export functionality in the admin GUI. However we (and some others) would like to do this as part of an automated process. There seem to have been some discussion on this topic and two existing modules that get pretty near our requirements:

However, they try to solve more then we need and for mindplay-dk's module, development seems to have discontinued. At that point I decided to build a more simple module with reduced scope that basically just makes ProcessWire's import/export automation-ready.

Thanks in advance for trying this out and any feedback!

About this Module

CAUTION: This module is incompatible with repeater fields and ProFields.

The module enables you to transfer template and field configuration from one processwire installation to another in an automated way.

  • Changes to templates or fields are exported to the file system immediately (so they can be added to source control together with changes in the template files)
  • The import script is designed to run from the command line (so it can be invoked from your build/deployment tool). On invocation in import mode,
    • a DB backup is created
    • template/field changes from the persist directory are imported into the DB
  • In restore mode, the import script can restore any of the DB backups previously saved

How to Use

  1. Make sure the module is installed in the source and destination ProcessWire environments.
  2. After installation of the module, you should check if the module's default persistDirectory configuration setting fits your requirements. The module will automatically export all fields, fieldgroups, and templates to JSON files in the directory specified by that setting. Note that the same setting is used by the import script as well, so if you change it, make sure you change it in all affected ProcessWire environments.
  3. The JSON files can be transferred to the destination ProcessWire environment.
  4. Running the import script from the command line will import template and field data in the destination ProcessWire environment.

Manual Installation

Caution: Beta software - do not use in a production environment without prior testing and regular back-ups.

Caution: This module is incompatible with repeater fields and ProFields.

In case automatic installation does not work, get the code at https://github.com/jaromic/pw-autoexport-tf/ and follow the instructions in README.md for manual installation.

Manual Uninstall

Delete the following files and directories from your module directory:

AutoExportTemplatesAndFields/
AutoExportTemplatesAndFields.module
 Download

Install from the module directory, clone the repository via GitHub, or download ZIP.

Edited by jaro
Statement about incompatibility added
  • Like 15

Share this post


Link to post
Share on other sites

Hi and welcome to the forums.

This sounds interesting. I definetly will try it out, but not soon. Maybe in a week or two.

The DB-backup integration looks good. :)

Do you have used it with namespaced PW version 3 too?

Share this post


Link to post
Share on other sites

Thanks, horst :)

Using that version in our project, I have developed and tested for 2.6 only so far. It does not use namespaces, so 3.x will probably not load the module. I will adapt and test with 2.7 and 3.x as soon as my time allows, hope to get to that within the next two weeks too.

  • Like 1

Share this post


Link to post
Share on other sites

Now, that's some nice first post to have in the forums, so first of all welcome here.

I just wanted to add a word of caution here. The export functionality should work well for core fieldtypes, but 3rd party fieldtypes might not export/import their settings correctly. Especially for more complex (db-wise) fieldtypes like Table or maybe Matrix it's often not so simple to export to a text format. E.g. FieldtypeOptions didn't export it's options for quite some time. 

Also I'd be cautious with calling modules discontinued, which is, at least for my module, not the truth. Not seeing a weekly changelog is not necessarily a bad thing. 

  • Like 2

Share this post


Link to post
Share on other sites

Thanks, and sorry, I just corrected that statement about your module.

Even if it cannot handle all field types that some other modules contribute, I hope I'll be able to improve my module to the point where it reliably warns about field types causing problems.

Share this post


Link to post
Share on other sites

@jaro @LostKobrakai

<dream mode>

Not sure if this is a good idea or not, but could this module be made to automatically export migrations that are compatible with Benjamin's migrations module? This would allow his module's interface to be used on the importing side to select which migrations to import.

</dream mode>

Edited to add: Now I've actually tried this module, I think the dream outlined above is more of a delusion. As it stands, the module does seem like a very neat way to keep the state of the fields and templates under version control along with the template files; nice work, @jaro!

Share this post


Link to post
Share on other sites
On 3.9.2016 at 1:59 PM, netcarver said:

Not sure if this is a good idea or not, but could this module be made to automatically export migrations that are compatible with Benjamin's migrations module? This would allow his module's interface to be used on the importing side to select which migrations to import.

Sorry it took me a while to answer, and thanks for the input and for trying it out!

The module is all about ProcessWire's built-in import/export functionality, merely exposing and automating it. For the moment I'd rather have it become good and stable in this than doing both formats mediocrely. For example, there are still issues with some common field types, and I want to look into special cases during import that are handled specially by the GUI when doing it graphically.

On 12.7.2016 at 5:01 PM, horst said:

Do you have used it with namespaced PW version 3 too?

In the meantime I did some tests with ProcessWire versions 2 and 3. The module itself worked without any changes both in v2 and v3 installations (thanks to ProcessWire's namespace magic), but I had to do differentiate in the import script. v1.0.1 contains that and some small fixes.

  • Like 1

Share this post


Link to post
Share on other sites

Hi,

I Installed the "AutoExportTemplatesAndFields" and when creating repeater fields the module was affecting the fields editing.

I had two repeater fields: "repeater1" and "repeater2", the "repeater1" should repeat the "images1" field and the "repeater2" should repeat the "images2",

the problem was each time I edited one of them and change the repeated field the other assumed that modification. Example: editing the "repeater1" and change the field to "image3" the "repeater2" instead of having the "image2" has the field to be repeated assumed the field "image3".

After uninstall the "AutoExportTemplatesAndFields" module I could edit each repeater and assign different fields to them.

I hope you can find the issue it is a great module to use.

Thank you.

  • Like 3

Share this post


Link to post
Share on other sites
On 1.4.2017 at 5:31 PM, vmo said:

I had two repeater fields [...] the problem was each time I edited one of them and change the repeated field the other assumed that modification. [...] I hope you can find the issue it is a great module to use.

Hi, thanks for that bug report, and I'm glad you like that module! I hope I'll have some time to look into this soon. I have added it to the issues on github for now.

  • Like 1

Share this post


Link to post
Share on other sites
On 4/6/2017 at 2:25 AM, jaro said:

Hi, thanks for that bug report, and I'm glad you like that module! I hope I'll have some time to look into this soon. I have added it to the issues on github for now.

Hi i ran into the same issue und it cost me much time to find the culprit of it. Please at least post a big warning in the readme for users to be aware before installation since i suspect this can affect many users who have installed pro fields

  • Like 1

Share this post


Link to post
Share on other sites
3 hours ago, ICF Church said:

Hi i ran into the same issue und it cost me much time to find the culprit of it. Please at least post a big warning in the readme for users to be aware before installation since i suspect this can affect many users who have installed pro fields

@ICF Church README has been updated. Thanks for your feedback.

  • Like 1

Share this post


Link to post
Share on other sites

This issue hit me a while back too with the RepeaterMatrix field. I ended up posting about it in the Profields support board but, embarrassingly, forgot to let you know about it at the time, jaro. My apologies to all for the oversight.

 

Share this post


Link to post
Share on other sites

The issue, which I'd like to call Agent Smith Bug, that caused a Repeater/RepeaterMatrix field copying itself onto other same type fields while erasing the contents of the fields happened to me inversely without warning. Fortunately, it happened on a site while it's in development. I installed the module way before while browsing for new modules in the directory, and I forgot it was ever installed. It was later I upgraded the core many times, and available modules with the ProcessWireUpgrade module and later I installed the ProFields.

I think we need a special cross-checking notification system, just like a product changes its price or availability in Amazon's shopping cart. One way it was achieved, while you're installing a module it shows a warning for the system version. Right there, a system should notify us with a critical warning that module x would possibly break the behavior of module y. In my case, it would be great if the ProFields installation notified me. But how can it know? (Reminds me the Project Insight scene of Winter Soldier) As humans, we can't check every issue, every board entry.  Hence we need a database, testers, modifiers, structural changes, etc. Too many resources, scratch this idea.

Share this post


Link to post
Share on other sites
On 1.4.2017 at 5:31 PM, vmo said:

I had two repeater fields: "repeater1" and "repeater2", the "repeater1" should repeat the "images1" field and the "repeater2" should repeat the "images2",

the problem was each time I edited one of them and change the repeated field the other assumed that modification. Example: editing the "repeater1" and change the field to "image3" the "repeater2" instead of having the "image2" has the field to be repeated assumed the field "image3".

 

On 2.11.2017 at 1:26 PM, adoxus said:

The issue, which I'd like to call Agent Smith Bug, that caused a Repeater/RepeaterMatrix field copying itself onto other same type fields while erasing the contents of the fields happened to me inversely without warning.

 

On 10.10.2017 at 1:34 PM, netcarver said:

This issue hit me a while back too with the RepeaterMatrix field.

 

On 9.10.2017 at 11:38 AM, ICF Church said:

Hi i ran into the same issue und it cost me much time to find the culprit of it.

 

Thanks guys for all the feedback.

I looked into this a little, and I was able to reproduce an instance of the problem using VMO's description with two repeater fields 'rep1' and 'rep2' and two text fields 'text1' and 'text2'. The assignment of text fields to repeater fields got mixed up if and only if the AutoExportTemplatesAndFieldsModule was installed.

I could narrow down the problem onto my use of ProcessWire's $field->getExportData() inside a hook 'after' ProcessPageView::finished. The problem is triggered when this function is called on the repeater fields in that hook, so the function seems to have side effects. I have added a minimal showcase for this called 'BreakRepeaterFields module' to the git repository, see module info summary for usage.

To sum this up: I am pretty confident there is no bug in my code directly causing the faulty behaviour. On the other hand one could not say that there is a bug in ProcessWire either, as my module is using an internal method which is not part of the documented API.

Best I can do for now is to declare this module incompatible with repeater fields and ProFields.

  • Thanks 1

Share this post


Link to post
Share on other sites

Thanks for looking into it @jaro!

Is there no possibility to check weather a field is / is used inside, a repeater and then treat it differently (or omitting it)? Since this solves a rather critical weakness of Processwire (imho), maybe @ryan can help out with this?

Share this post


Link to post
Share on other sites
7 minutes ago, noelboss said:

Thanks for looking into it @jaro!

Is there no possibility to check weather a field is / is used inside, a repeater and then treat it differently (or omitting it)? Since this solves a rather critical weakness of Processwire (imho), maybe @ryan can help out with this?

Fields could be omitted by type, but the output of this module would then not be a complete snapshot of templates and fields any more, which was its purpose in the first place. Do you think, such an incomplete snapshot (without repeater fields and similar) could still be useful for repeater field users?

Treating problematic fields differently could solve the problem, but the module would most probably have to be equipped with code for each problematic field type.

Yes of course, one or two hints from @ryan could be very helpful now :)

Share this post


Link to post
Share on other sites

I think a partial export is still better then breaking an entire system ;) So even if it does not do anything, it's still better to if-repeater-return than to do harm imho. You could still log a warning that there have been unsupported fields that need manual exporting so the user knows what fields need to be exported…

Now, as for me, i just had to manually copy a field (not repeater) that I otherwise could have just exported - imported… (which I now did via the db directly)…

Also, shouldn't it be possible to narrow down the problem even further now that we know what causes the problem? What happens if you use "getTableData()" directly?

 

  • Like 1

Share this post


Link to post
Share on other sites
50 minutes ago, noelboss said:

I think a partial export is still better then breaking an entire system ;) So even if it does not do anything, it's still better to if-repeater-return than to do harm imho. You could still log a warning that there have been unsupported fields that need manual exporting so the user knows what fields need to be exported…

So far, I haven't heard of any case where using this module "breaks an entire system". However, you are claiming that it "nuked [your] system" in your article as well (linking here). I must say I'm really surprised to read about what sounds far worse than the problems mentioned so far by you or anyone else in this thread. Can you please provide some details on what happened there? Thanks.

Share this post


Link to post
Share on other sites

Hi Jaro, sorry for the long delay.

Now, nuked is probably a strong word, sorry if that offended you, that was not my intention and I can change that.

Now to as what happened: I stored some Configuration (like meta-data, logo, global site info etc) of my site in a Repeater Matrix structure (would rather user functional fields but they don't support all kinds of fields like images etc.) – and I also used several other repeaters on my site. Now whenever I made changes to any of them, the other Repeaters where changed as well, deleting my work I put into creating them and also the data that each of the already existing repeaters held. Thus breaking my site in some cases (where it dependet on configurations beeing present) and losing work, data stored as well as work I put into structuring things.

For example: I created a repeater for Social Media Links and started filling these in. After that I would create another Repeater for Multiple Information Junks. – Now my Configuration Repeater would lose its data, its setup and the same happened with the Social Media Links repeater. I would lose its data plus its setup. I had to recreate the Configuration Repeater and the Social Media Repeater and input the data again.

Until i found the culprit, I lost quite some hours of development work. And it was not obvious from where the problem stemed. At first I thought Repeater was broken, or my setup was wrong (I'm fairly new to PW).

In my humble opinion, dataloss is probably the worst that could happen to a system. A PHP Error, no Problem, remove the module, fix the code. Loss of files – they are under GIT, some work might be lost but not much. But data loss, even more important if it's structural – thats really bad. Things get worse if it's not obvious what causes this data to disappear.

I think, all of this is the case here. Hope this explains it a bit better. If I can be of any help in solving this issue, let me know. BTW, you said

On 11/6/2017 at 10:10 AM, jaro said:

but the output of this module would then not be a complete snapshot of templates and fields any more

with this issue, this is not the case anyway because the module can not handle the repeaters correctly and thus also not export its config corretly, thus the output is not a complete snapshot in the first place ;)

 

Share this post


Link to post
Share on other sites

Sorry for the even longer delay – as always, the weeks before christmas are the busiest of the year.

On 9.11.2017 at 11:09 AM, noelboss said:

Now, nuked is probably a strong word, sorry if that offended you, that was not my intention and I can change that.

No worries, I don't feel offended personally, it's just bad PR and that it kind of looks like some careless coding of this module caused data loss. I'd appreciate if you could reword or just remove the link.

Thanks for the detailed explanation.

On 9.11.2017 at 11:09 AM, noelboss said:

with this issue, this is not the case anyway because the module can not handle the repeaters correctly and thus also not export its config corretly, thus the output is not a complete snapshot in the first place ;)

I agree, but that's not how I meant it anyway, I was referring to the partial export vs. clean fail design choice.

Sticking to the second, I have added a blacklist of known incompatible fieldtypes (containing only repeater so far) for now so the module will not only skip incompatible fields, but refuse to export all fields with a clear error message in that case.

  • Like 1

Share this post


Link to post
Share on other sites

Hi @jaro

Thanks for the update. Would it be possible to still have a partial export (after checking a confirmation or using module settings)?

I have removed the links :)

  • Like 1

Share this post


Link to post
Share on other sites

Hi @jaro,

I've been having a look at the Repeater issue and the BreakRepeaterFields demonstration.

Interestingly, the issue is not that fields are copied from one repeater to another. It is that the module interferes with the listing of fields when the repeater field settings are viewed in ProcessField, causing the fields of one repeater to appear in the AsmSelect of another repeater. So if you check the database the fields associated with each repeater is actually correct despite the incorrect listing shown in ProcessField. But if the user then saves the field in ProcessField it is at this point that the associated fields become incorrect.

Could you explain why the module needs to hook ProcessPageView::finished? This method fires on every page view, front-end and back-end. But most of these page views will have no connection to field settings or template settings changing. Instead of hooking this method, couldn't you hook only methods that are related to field and template settings? So some method in ProcessField and ProcessTemplate?

And also, the module is looping over all fields on every page view. Could you focus in on just the field that is being edited? So when field1 is edited in ProcessField, just export the data for field1 rather than looping over every field. This would avoid the situation where the data for repeater2 becomes involved when editing repeater1.

I should say that I've just had a brief look at the issue so far, so there might be good reasons why the module does what it does.

  • Like 4
  • Thanks 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By dreerr
      TemplateEnginePug (formally TemplateEngineJade)
       
      This module adds Pug templates to the TemplateEngineFactory. It uses https://github.com/pug-php/pug to render templates.
      doctype html html(lang='en') head meta(http-equiv='content-type', content='text/html; charset=utf-8') title= $page->title link(rel='stylesheet', type='text/css', href=$config->urls->templates . 'styles/main.css') body include header.pug h1= $page->title if $page->editable() p: a(href=$page->editURL) Edit Project on GitHub: github.com/dreerr/TemplateEnginePug
      Project in modules directory: modules.processwire.com/modules/template-engine-pug/
       
      For common problems/features/questions about the Factory, use the TemplateEngineFactory thread.
       
    • By tpr
      ProcessNetteTester
      Run Nette Tester tests within ProcessWire admin.
      (continued from here)

      Features
      AJAX interface for running Nette Tester tests, in bulk or manually display counter, error message and execution time in a table run all tests at once or launch single tests show formatted test error messages and report PHP syntax errors stop on first failed test (optional) hide passed tests (optional) display failed/total instead passed/total (optional) re-run failed tests only (optional) auto scroll (optional) include or exclude tests based on query parameters start/stop all tests with the spacebar reset one test or all tests (ctrl+click) https://modules.processwire.com/modules/process-nette-tester/
      https://github.com/rolandtoth/ProcessNetteTester
    • By bernhard
      Some of you might have followed the development of this module here: https://processwire.com/talk/topic/15524-previewdiscussion-rockdatatables/ . It is the successor of "RockDataTables" and requires RockFinder to get the data for the grid easily and efficiently. It uses the open source part of agGrid for grid rendering.
       
      WHY?
      ProcessWire is awesome for creating all kinds of custom backend applications, but where it is not so awesome in my opinion is when it comes to listing this data. Of course we have the built in page lister and we have ListerPro, but none of that solutions is capable of properly displaying large amounts of data, for example lists of revenues, aggregations, quick and easy sorts by the user, instant filter and those kind of features. RockGrid to the rescue 😉 
       
      Features/Highlights:
      100k+ rows Instant (client side) filter, search, sort (different sort based on data type, eg "lower/greater than" for numbers, "contains" for strings) extendable via plugins (available plugins at the moment: fullscreen, csv export, reload, batch-processing of data, column sum/statistics, row selection) all the agGrid features (cell renderers, cell styling, pagination, column grouping etc) vanilla javascript, backend and frontend support (though not all plugins are working on the frontend yet and I don't plan to support it as long as I don't need it myself)  
      Limitations:
      While there is an option to retrieve data via AJAX the actual processing of the grid (displaying, filtering, sorting) is done on the client side, meaning that you can get into troubles when handling really large datasets of several thousands of rows. agGrid should be one of the most performant grid options in the world (see the official example page with a 100k row example) and does a lot to prevent problems (such as virtual row rendering), but you should always have this limitation in mind as this is a major difference to the available lister options that do not have this limitation.
      Currently it only supports AdminThemeUikit and I don't plan to support any other admin theme.
       
      Download: https://gitlab.com/baumrock/RockGrid
      Installation: https://gitlab.com/baumrock/RockGrid/wikis/Installation
      Quikckstart: https://gitlab.com/baumrock/RockGrid/wikis/quickstart
      Further instructions: https://gitlab.com/baumrock/RockGrid/wikis/quickstart#further-instructions
       
      Module status: alpha, License: MIT
      Note that every installation and uninstallation sends an anonymous google analytics event to my google analytics account. If you don't want that feel free to remove the appropriate lines of code before installation/uninstallation.
       
      Contribute:
      You can contribute to the development of this and other modules or just say thank you by
      testing, reporting issues and making PRs at gitlab liking this post buying me a drink: paypal.me/baumrock/5 liking my facebook page: facebook.com/baumrock hiring me for pw work: baumrock.com  
      Support: Please note that this module might not be as easy and plug&play as many other modules. It needs a good understanding of agGrid (and JavaScript in general) and it likely needs some looks into the code to get all the options. Please understand that I can not provide free support for every request here in the forum. I try to answer all questions that might also help others or that might improve the module but for individual requests I offer paid support for 60€ per hour.
       
      Changelog
      180711 bugfix (naming issue) 180630 alpha realease  
      Use Cases / Examples:
      Colored grid cells, Icons, Links etc. The Grid also has a "batcher" feature built in that helps communicating with the server via AJAX and managing resource intensive tasks in batches:

      Filters, PW panel links and instant reload on panel close:

      You can combine the grid with a chart library like I did with the (outdated) RockDataTables module:

    • By tpr
      Update 2018-07-09: ProcessNetteTester module is available in the Modules Directory and on GitHub.

      This is a short tutorial on how to use Nette Tester with ProcessWire.
      As you will see it's very easy to setup and use and it's perfect for testing your code's functionality. With bootstrapping ProcessWire it's also possible to check the rendered markup of pages using the API, checking page properties, etc. It's also a great tool for module developers for writing better code. 
      While there will be nothing extraordinary here that you couldn't find in Tester's docs this can serve as a good starting point.
      Prerequisites: PHP 5.6+
      01 Download Tester
      Go to https://github.com/nette/tester/releases and download the latest release (currently 2.0.2). Download from the link reading "Source code (zip)". You can use composer also if you wish.
      02 Extract Tester files
      Create a new directory in your site root called "tester". Extract the zip downloaded here, so it should look like this:
      /site /tester/src /tester/tools /tester/appveyor.yml /tester/composer.json /tester/contributing.md /tester/license.md /tester/readme.md /wire ... 03 Create directory for test files
      Add a new directory in "/tester" called "tests". Tester recognizes "*.Test.php" and "*.phpt" files in the tests directory, recursively. 
      04 Create your first test
      In the "tests" directory create a new "MyTest.php" file.
      The first test is a very simple one that bootstraps ProcessWire and checks if the Home page name is "Home". This is not the smartest test but will show you the basics.
      Add this to "/tester/tests/MyTest.php":
      <?php namespace ProcessWire; use \Tester\Assert; use \Tester\DomQuery; use \Tester\TestCase; use \Tester\Environment; require __DIR__ . '/../src/bootstrap.php'; // load Tester require __DIR__ . '/../../index.php'; // bootstrap ProcessWire Environment::setup(); class MyTest extends TestCase {     // first test (step 04)     public function testHomeTitle()     {         $expected = 'Home'; // we expect the page title to be "Home"         $actual = wire('pages')->get(1)->title; // check what's the actual title Assert::equal($expected, $actual); // check whether they are equal     }     // second test will go here (step 06)     // third test will go here (step 07) } // run testing methods (new MyTest())->run(); I've added comment placeholders for the second and third tests that we will insert later.
      05 Run Tester
      Tester can be run either from the command line or from the browser. The command line output is more verbose and colored while in the browser it's plain text only (see later).
      Running from the command line
      Navigate to the "/tester" directory in your console and execute this:
      php src/tester.php -C tests This will start "/tester/src/tester.php" and runs test files from the "/tester/tests" directory. The "-C" switch tells Tester to use the system-wide php ini file, that is required here because when bootstrapping ProcessWire you may run into errors (no php.ini file is used by default). You may load another ini file with the "-c <path>" (check the docs).
      If the title of your Home page is "Home" you should see this:

      If it's for example "Cats and Dogs", you should see this:

      Running from the browser
      First we need to create a new PHP file in ProcessWire's root, let's call it "testrunner.php". This is because ProcessWire doesn't allow to run PHP files from its "site" directory.
      The following code runs two test classes and produces a legible output. IRL you should probably iterate through directories to get test files (eg. with glob()), and of course it's better not allow tests go out to production.
      <?php ini_set('html_errors', false); header('Content-type: text/plain'); echo 'Starting tests.' . PHP_EOL; echo '--------------------------' . PHP_EOL; $file = __DIR__ . '/PATH_TO/FirstTest.php'; echo basename($file) . ' '; require $file; echo '[OK]' . PHP_EOL; $file = __DIR__ . '/PATH_TO/SecondTest.php'; echo basename($file) . ' '; require $file; echo '[OK]' . PHP_EOL; echo '--------------------------' . PHP_EOL; echo 'Tests finished.'; exit; Navigate to "DOMAIN/testrunner.php" in your browser to execute the file. If every test succeeds you should get this:

      If there are failed tests the execution stops and you can read the error message. If there were more tests (eg. ThirdTest), those won't be displayed under the failed test.

      06 DOM test
      This test will check if a page with "basic-page" template has a "h1" element. We will create the page on the fly with ProcessWire's API. To keep things simple we will add the new test as a new method to our MyTest class.
      Add this block to the MyTest class:
      public function testBasicPageHeadline() {     $p = new Page();     $p->template = 'basic-page';     $html = $p->render();     $dom = DomQuery::fromHtml($html);     Assert::true($dom->has('h1')); } This will most likely be true but of course you can check for something more specific, for example "div#main". Note that we have used the DomQuery helper here (check the "use" statement on the top of the file).
      07 Custom function test
      You will probably want to make sure your custom functions/methods will work as they should so let's write a test that demonstrates this.
      I don't want to complicate things so I'll check if the built-in "pageName" sanitizer works as expected. Add this to the myTest class:
      public function testPageNameSanitizer() {     $expected = 'hello-world';     $actual = wire('sanitizer')->pageName('Hello world!', true);     Assert::equal($expected, $actual); } This should also be true. Try to change the expected value if you are eager to see a failure message.
       
      08 Next steps
      You can add more methods to the MyTest class or create new files in the "tests" directory. Check out the range of available Assertions and other features in the docs and see how they could help you writing more fail-safe code.
      Once you make a habit of writing tests you'll see how it can assist making your code more bulletproof and stable. Remember: test early, test often 🙂
      If you find out something useful or cool with Tester make sure to share.
    • By bernhard
      @Sergio asked about the pdf creation process in the showcase thread about my 360° feedback/survey tool and so I went ahead and set my little pdf helper module to public.
      Description from PW Weekly:
       
      Download & Docs: https://gitlab.com/baumrock/RockPdf
       
      You can combine it easily with RockReplacer: 
      See also a little showcase of the RockPdf module in this thread: