├── .devcontainer └── devcontainer.json ├── .editorconfig ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE ├── dependabot.yml └── workflows │ └── laravel.yml ├── .gitignore ├── .travis.yml ├── .vscode └── settings.json ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── LICENSE ├── README.md ├── caffeine.jpg ├── composer.json ├── config ├── .gitkeep └── genealabs-laravel-caffeine.php ├── docker-compose.yml ├── phpunit.xml ├── resources └── views │ └── script.blade.php ├── routes └── web.php ├── src ├── Console │ └── Commands │ │ └── Publish.php ├── Dripper.php ├── Http │ ├── Controllers │ │ └── Drip.php │ └── Middleware │ │ └── LaravelCaffeineDripMiddleware.php └── Providers │ └── Service.php └── tests ├── CreatesApplication.php ├── Feature └── CaffeineTest.php ├── FeatureTestCase.php ├── Fixtures ├── expired_script.txt ├── partial_script.txt └── unexpired_script.txt ├── Http └── Controllers │ └── Test.php ├── Unit ├── Console │ └── Commands │ │ └── PublishTest.php └── DripperTest.php ├── UnitTestCase.php ├── resources └── views │ └── tests │ ├── disabled.blade.php │ ├── form.blade.php │ └── layout.blade.php └── routes └── web.php /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // https://aka.ms/devcontainer.json 2 | { 3 | "name": "Existing Docker Compose (Extend)", 4 | "dockerComposeFile": [ 5 | "../docker-compose.yml" 6 | ], 7 | "features": { 8 | "ghcr.io/devcontainers/features/sshd:1": { 9 | "version": "latest" 10 | } 11 | }, 12 | "service": "laravel.test", 13 | "workspaceFolder": "/var/www/html", 14 | "customizations": { 15 | "vscode": { 16 | "settings": {}, 17 | "extensions": [ 18 | "aaron-bond.better-comments", 19 | "adrianwilczynski.alpine-js-intellisense", 20 | "AlexArthurs.todo-pusher", 21 | "amiralizadeh9480.laravel-extra-intellisense", 22 | "austenc.laravel-blade-spacer", 23 | "beyondcode.tinkerwell", 24 | "bmewburn.vscode-intelephense-client", 25 | "bradlc.vscode-tailwindcss", 26 | "christian-kohler.npm-intellisense", 27 | "christian-kohler.path-intellisense", 28 | "cierra.livewire-vscode", 29 | "codecov.codecov", 30 | "codingyu.laravel-goto-view", 31 | "davidanson.vscode-markdownlint", 32 | "davidbwaters.macos-modern-theme", 33 | "eamodio.gitlens", 34 | "editorconfig.editorconfig", 35 | "ericcheng.codesongclear", 36 | "faelv.composer-companion", 37 | "file-icons.file-icons", 38 | "foxundermoon.shell-format", 39 | "georgykurian.laravel-ide-helper", 40 | "github.codespaces", 41 | "GitHub.copilot-chat", 42 | "GitHub.copilot-nightly", 43 | "GitHub.copilot", 44 | "github.vscode-github-actions", 45 | "github.vscode-pull-request-github", 46 | "Gruntfuggly.todo-tree", 47 | "heissenbergerlab.php-array-from-json", 48 | "heybourn.headwind", 49 | "huibizhang.codesnap-plus", 50 | "irongeek.vscode-env", 51 | "kencocaceo.customvscodeuicss", 52 | "m4ns0ur.base64", 53 | "maciejdems.add-to-gitignore", 54 | "mahmoudshahin.laravel-routes", 55 | "markis.code-coverage", 56 | "martybegood.single-editor-tabs", 57 | "mechatroner.rainbow-csv", 58 | "mehedidracula.php-namespace-resolver", 59 | "mhutchie.git-graph", 60 | "mikestead.dotenv", 61 | "mohamedbenhida.laravel-intellisense", 62 | "mrmlnc.vscode-duplicate", 63 | "naoray.laravel-goto-components", 64 | "oderwat.indent-rainbow", 65 | "pcbowers.alpine-intellisense", 66 | "recca0120.vscode-phpunit", 67 | "redhat.vscode-yaml", 68 | "rifi2k.format-html-in-php", 69 | "shevaua.phpcs", 70 | "shufo.vscode-blade-formatter", 71 | "sperovita.alpinejs-syntax-highlight", 72 | "streetsidesoftware.code-spell-checker", 73 | "syler.ignore", 74 | "teabyii.ayu", 75 | "usernamehw.errorlens", 76 | "vincaslt.highlight-matching-tag", 77 | "WakaTime.vscode-wakatime", 78 | "withfig.fig", 79 | "xdebug.php-debug" 80 | ] 81 | } 82 | }, 83 | "remoteUser": "sail", 84 | "postCreateCommand": "sudo chown -R 1000:1000 /var/www/html", 85 | "forwardPorts": [ 86 | 80, 87 | 5432, 88 | 6001, 89 | 8025, 90 | 8900, 91 | 9000 92 | ], 93 | "portsAttributes": { 94 | "80": { 95 | "label": "HTTP" 96 | }, 97 | "5432": { 98 | "label": "Postgres" 99 | }, 100 | "6001": { 101 | "label": "Web Sockets" 102 | }, 103 | "8025": { 104 | "label": "MailHog" 105 | }, 106 | "8900": { 107 | "label": "Minio Console" 108 | }, 109 | "9000": { 110 | "label": "Minio Host" 111 | } 112 | }, 113 | "mounts": [ 114 | "source=${localEnv:HOME}/.wakatime.cfg,target=/home/sail/.wakatime.cfg,type=bind,consistency=delegated" 115 | ] 116 | // "runServices": [], 117 | // "shutdownAction": "none", 118 | } 119 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | indent_size = 2 14 | 15 | [*.{yml,yaml}] 16 | indent_size = 2 17 | 18 | [.blackfire.yaml] 19 | indent_size = 4 -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [mikebronner] 4 | patreon: # mikebronner 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE: -------------------------------------------------------------------------------- 1 | ## Expected Behavior 2 | 3 | ## Actual Behavior 4 | 5 | ## Environment 6 | - PHP Version: 7 | - Laravel Version: 8 | - LaravelCaffeine Version: 9 | 10 | ## Stack Trace 11 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | registries: 3 | git-nova-laravel-com: 4 | type: git 5 | url: https://nova.laravel.com 6 | username: mike@genealabs.com 7 | password: "${{secrets.GIT_NOVA_LARAVEL_COM_PASSWORD}}" 8 | 9 | updates: 10 | - package-ecosystem: composer 11 | directory: "/" 12 | schedule: 13 | interval: daily 14 | time: "13:00" 15 | open-pull-requests-limit: 10 16 | registries: 17 | - git-nova-laravel-com 18 | -------------------------------------------------------------------------------- /.github/workflows/laravel.yml: -------------------------------------------------------------------------------- 1 | name: Laravel Package 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | laravel-tests: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | fail-fast: true 16 | matrix: 17 | php: [8.3, 8.2] 18 | 19 | name: PHP ${{ matrix.php }} 20 | 21 | steps: 22 | - name: Checkout code 23 | uses: actions/checkout@v3 24 | 25 | - name: Cache dependencies 26 | uses: actions/cache@v4 27 | with: 28 | path: ~/.composer/cache/files 29 | key: dependencies-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }} 30 | 31 | - name: Setup PHP ${{ matrix.php }} 32 | uses: shivammathur/setup-php@v2 33 | with: 34 | php-version: ${{ matrix.php }} 35 | extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, gd, pgsql, pdo_pgsql 36 | coverage: none 37 | 38 | - name: Install Dependencies 39 | run: | 40 | composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist 41 | 42 | - name: Execute Integration and Feature tests via PHPUnit 43 | run: vendor/bin/phpunit --configuration phpunit.xml --testsuite Integration,Feature 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .phpunit.result.cache 2 | .phpunit.cache 3 | /tests/Browser/console 4 | /tests/Browser/screenshots 5 | /vendor 6 | composer.lock 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | language: php 3 | sudo: required 4 | 5 | addons: 6 | chrome: stable 7 | 8 | php: 9 | - 7.2 10 | - 7.3 11 | - 8.1 12 | - 8.2 13 | 14 | before_script: 15 | - travis_retry composer self-update 16 | - travis_retry composer install --no-interaction --dev --prefer-dist --no-suggest 17 | - google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost & 18 | 19 | script: 20 | - ./vendor/bin/phpunit --coverage-text --coverage-clover ./build/logs/clover.xml 21 | 22 | after_script: 23 | - php vendor/bin/coveralls 24 | - wget https://scrutinizer-ci.com/ocular.phar 25 | - php ocular.phar code-coverage:upload --format=php-clover ./build/logs/clover.xml 26 | 27 | notifications: 28 | webhooks: 29 | urls: 30 | - https://webhooks.gitter.im/e/30886f28c25b1e31088f 31 | on_success: change # options: [always|never|change] default: always 32 | on_failure: always # options: [always|never|change] default: always 33 | on_start: never # options: [always|never|change] default: always 34 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "autoload", 4 | "autoloader", 5 | "Bronner", 6 | "classmap", 7 | "Genea", 8 | "genealabs", 9 | "jenssegers", 10 | "laravel", 11 | "Laravel", 12 | "phpmd", 13 | "phpunit", 14 | "testbench" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [7.0.2] - 2020-03-11 4 | ### Fixed 5 | - problems with DOM parsing and reverted back to RegExp. 6 | 7 | ## [7.0.1] - 2020-03-06 8 | ### Updated 9 | - dependencies for Laravel 7 compatibility, removed temp dependencies. 10 | 11 | ## [7.0.0] - 2020-02-29 12 | ### Added 13 | - Laravel 7 compatibility. 14 | 15 | ### Fixed 16 | - asset insertion functionality. 17 | 18 | ## [1.0.5] - 2019-11-28 19 | ### Updated 20 | - readme with Voyager incompatibility warning and suggested work-around. 21 | 22 | ## [1.0.4] - 2019-10-08 23 | ### Fixed 24 | - commits not being applied to previous release. 25 | 26 | ## [1.0.3] - 2019-10-08 27 | ### Updated 28 | - dependency compatibilies. 29 | 30 | ## [1.0] - 2019-09-05 31 | ### Added 32 | - Laravel 6.0 compatibility. 33 | 34 | ### Removed 35 | - compatibility with older versions of Laravel. 36 | 37 | ## [0.8.3] - 2019-06-30 38 | ### Added 39 | - support for Spatie's `laravel-csp` package. 40 | 41 | ## [0.8.2] - 2019-06-30 42 | ### Changed 43 | - method of checking registered middleware groups to use `hasMiddlewareGroup()`. 44 | 45 | ## [0.6.12] - 5 Aug 2018 46 | ### Fixed 47 | - middleware response to be a view instead of string. Thanks @dallincoons, #96 #95. 48 | 49 | ## [0.6.11] - 13 May 2018 50 | ### Fixed 51 | - regexp to be simpler. Thanks @juandi, #92. 52 | - `app_env` (to `internaltesting`) to avoid testing conflicts. Thanks @agjino, #82. 53 | 54 | ## [0.6.10] - 13 May 2018 55 | ### Fixed 56 | - erroneous `const` in JavaScript, changed to `var`. Thanks @netpok, #86. 57 | 58 | ## [0.6.9] - 13 May 2018 59 | ### Fixed 60 | - erroneous `let` in JavaScript, changed to `var`. Thanks @spaceemotion, #94. 61 | 62 | ## [0.6.8] - 15 Feb 2018 63 | ### Fixed 64 | - dependency versions to allow installation on earlier versions of Laravel. 65 | 66 | ## [0.6.7] - 9 Feb 2018 67 | ### Added 68 | - Laravel 5.6 compatibility. 69 | 70 | ## [0.6.6] - 9 Jan 2018 71 | ### Changed 72 | - testing to use orchestral/testbench suite. 73 | 74 | ## [0.6.5] - 5 Jan 2018 75 | ### Added 76 | - Laravel 5.6 compatibility. 77 | 78 | ## [0.6.6] - 9 Feb 2018 79 | ### Changed 80 | - tests to use `orchestral/testbench` suite. 81 | 82 | ## [0.6.5] - 5 Jan 2018 83 | ### Added 84 | - `thanks` package. 85 | 86 | ### Updated 87 | - documentation and change-log. 88 | 89 | ## [0.6.4] - 5 Jan 2018 90 | ### Fixed 91 | - composer dependency version constraints (only Laravel 5.4 and 5.5 have been tested). 92 | 93 | ## [0.6.3] - 14 Dec 2017 94 | ### Fixed 95 | - middleware registration to detect apache server. 96 | 97 | ## [0.6.2] - 11 Dec 2017 98 | ### Added 99 | - route middleware functionality. 100 | 101 | ### Changed 102 | - config variable to `outdated-drip-check-interval`. 103 | 104 | ### Fixed 105 | - naming of config setting `drip-interval`. 106 | - formatting of script fixture. 107 | 108 | ## [0.6.1] - 10 Dec 2017 109 | ### Added 110 | - ability to exclude a page from caffinating the application via meta tag. 111 | 112 | ## [0.6.0] - 9 Dec 2017 113 | ### Added 114 | - drip timeout check and force page refresh if timeout occurred. 115 | 116 | ### Changed 117 | - config file setting names to be more explicit. 118 | - middleware is injected only when called from a web page or during testing. 119 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hello@genealabs.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | We welcome everyone to submit pull requests with: 3 | - fixes for issues 4 | - change suggestions 5 | - updateing of documentation 6 | 7 | However, not every pull request will automatically be accepted. I will review each carefully to make sure it is in line with 8 | the direction I want the package to continue in. This might mean that some pull requests are not accepted, or might stay 9 | unmerged until a place for them can be determined. 10 | 11 | ## Testing 12 | - [ ] After making your changes, make sure the tests still pass. 13 | - [ ] When adding new functionality, also add new tests. 14 | - [ ] Make sure there are no build errors on our CI server (https://ci.genealabs.com/build-status/view/6) 15 | - [ ] All code must past PHPCS and PHPMD PSR2 validation. 16 | 17 | ## Submitting changes 18 | When submitting a pull request, it is important to make sure to complete the following: 19 | - [ ] Add a descriptive header that explains in a single scentence what problem the PR solves. 20 | - [ ] Add a detailed description with animated screengrab GIFs vidualizing how it works. 21 | - [ ] Explain why you think it should be implemented one way vs. another, highlight performance improvements, etc. 22 | 23 | ## Coding conventions 24 | Start reading our code and you'll get the hang of it. We optimize for readability: 25 | - indent using four spaces (soft tabs) 26 | - use Blade for all views 27 | - avoid logic in views, put it in controllers or service classes 28 | - ALWAYS put spaces after list items and method parameters (`[1, 2, 3]`, not `[1,2,3]`), around operators (`x += 1`, not `x+=1`), and around hash arrows. 29 | - this is open source software. Consider the people who will read your code, and make it look nice for them. It's sort of like driving a car: Perhaps you love doing donuts when you're alone, but with passengers the goal is to make the ride as smooth as possible. 30 | - emphasis readability of code over patterns to reduce mental debt 31 | - always add an empty line around structures (if statements, loops, etc.) 32 | 33 | Thanks! 34 | Mike Bronner, GeneaLabs 35 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Issue 2 | *summarize your issue here* 3 | 4 | ## Environment 5 | Laravel Version: *x.y.z* 6 | Laravel Caffeine Package Version: *x.y.z* 7 | PHP Version: *x.y.z* 8 | Homestead Version: *x.y* 9 | 10 | ## Stack Trace 11 | - [ ] I have cleared my Laravel log file. 12 | - [ ] I have then reproduced my issue. 13 | - [ ] I have copied the __first__ listed stack trace from the fresh log file. 14 | 15 | ``` 16 | *paste the first stack trace here* 17 | ``` 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 - 2017 GeneaLabs, LLC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Caffeine for Laravel 2 | [![Travis](https://img.shields.io/travis/GeneaLabs/laravel-caffeine.svg)](https://travis-ci.org/GeneaLabs/laravel-caffeine) 3 | [![Scrutinizer](https://img.shields.io/scrutinizer/g/GeneaLabs/laravel-caffeine.svg)](https://scrutinizer-ci.com/g/GeneaLabs/laravel-caffeine) 4 | [![Coveralls](https://img.shields.io/coveralls/GeneaLabs/laravel-caffeine.svg)](https://coveralls.io/github/GeneaLabs/laravel-caffeine) 5 | [![GitHub (pre-)release](https://img.shields.io/github/release/GeneaLabs/laravel-caffeine/all.svg)](https://github.com/GeneaLabs/laravel-caffeine) 6 | [![Packagist](https://img.shields.io/packagist/dt/GeneaLabs/laravel-caffeine.svg)](https://packagist.org/packages/genealabs/laravel-caffeine) 7 | 8 | ![Caffeine for Laravel masthead image.](https://repository-images.githubusercontent.com/40729869/26446500-f1b2-11e9-9611-6a2e65688de2) 9 | 10 | ## Supporting This Package 11 | This is an MIT-licensed open source project with its ongoing development made possible by the support of the community. If you'd like to support this, and our other packages, please consider [becoming a sponsor](https://github.com/sponsors/mikebronner). 12 | 13 | We thank the following sponsors for their generosity. Please take a moment to check them out: 14 | 15 | - [LIX](https://lix-it.com) 16 | 17 | ## Goal 18 | Prevent forms from timing out when submitting them after leaving them on-screen 19 | for a considerable amount of time. (Laravel defaults to 120 minutes, but that 20 | is configurable and could be different site-by-site.) 21 | 22 | ## Implementation 23 | To achieve this, we are sending a caffeine-drip (a request at regular intervals) 24 | to keep the session from timing out. 25 | This is only implemented on pages with a `_token` field, so all other pages will 26 | time-out as normal. 27 | 28 | ## Reasoning 29 | I chose this approach to keep the integrity of site-security, by avoiding the 30 | following: 31 | - exposing the CSRF Token on an unsecured endpoint. 32 | - eliminating CSRF Token validation on specific routes, or even altogether. 33 | - removing session-timeout on all pages. 34 | 35 | ## Considerations 36 | ### Incompatible Packages 37 | - [Voyager](https://github.com/the-control-group/voyager) has been reported as 38 | being incompatible. To work around this, configure Caffeine to use 39 | route-based middleware on all non-Voyager routes. See details below for 40 | configuration and implementation of route-based middleware. 41 | 42 | ### Routes 43 | This package adds the routes under `genealabs/laravel-caffeine`. 44 | 45 | ### Dependencies 46 | Your project must fullfill the following: 47 | - Laravel 8.0 or higher 48 | - PHP 7.3 or higher. 49 | 50 | ## Installation 51 | ```sh 52 | composer require genealabs/laravel-caffeine 53 | ``` 54 | 55 | ## Upgrade Notes 56 | If you have previously registered the middleware, please remove the following 57 | middleware from `app/Http/Kernel.php`: 58 | ```php 59 | // protected $middleware = [ 60 | GeneaLabs\LaravelCaffeine\Http\Middleware\LaravelCaffeineDripMiddleware::class, 61 | // ]; 62 | ``` 63 | 64 | ### 0.6.0 65 | This update changes the config file setting names. Please delete the published 66 | config file `config/genealabs-laravel-caffeine.php` if it exists, and follow the 67 | configuration instructions below. 68 | 69 | ## Configuration 70 | ```php 71 | return [ 72 | /* 73 | |-------------------------------------------------------------------------- 74 | | Drip Interval 75 | |-------------------------------------------------------------------------- 76 | | 77 | | Here you may configure the interval with which Caffeine for Laravel 78 | | keeps the session alive. By default this is 5 minutes (expressed 79 | | in milliseconds). This needs to be shorter than your session 80 | | lifetime value configured set in "config/session.php". 81 | | 82 | | Default: 300000 (int) 83 | | 84 | */ 85 | 'drip-interval' => 300000, 86 | 87 | /* 88 | |-------------------------------------------------------------------------- 89 | | Domain 90 | |-------------------------------------------------------------------------- 91 | | 92 | | You may optionally configure a separate domain that you are running 93 | | Caffeine for Laravel on. This may be of interest if you have a 94 | | monitoring service that queries other apps. Setting this to 95 | | null will use the domain of the current application. 96 | | 97 | | Default: null (null|string) 98 | | 99 | */ 100 | 'domain' => null, 101 | 102 | /* 103 | |-------------------------------------------------------------------------- 104 | | Drip Endpoint URL 105 | |-------------------------------------------------------------------------- 106 | | 107 | | Sometimes you may wish to white-label your app and not expose the AJAX 108 | | request URLs as belonging to this package. To achieve that you can 109 | | rename the URL used for dripping caffeine into your application. 110 | | 111 | | Default: 'genealabs/laravel-caffeine/drip' (string) 112 | | 113 | */ 114 | 'route' => 'genealabs/laravel-caffeine/drip', // Customizable end-point URL 115 | 116 | /* 117 | |-------------------------------------------------------------------------- 118 | | Checking for Lapsed Drips 119 | |-------------------------------------------------------------------------- 120 | | 121 | | If the browser tab is suspended due to inactivity or the device is put to 122 | | sleep, it will still cause an error when trying to submit the form. To 123 | | avoid this, we force-reload the form 2 minutes prior to session 124 | | time-out or later. Setting this setting to 0 will disable this 125 | | check if you don't want to use it. 126 | | 127 | | Default: 2000 (int) 128 | | 129 | */ 130 | 'outdated-drip-check-interval' => 2000, 131 | 132 | /* 133 | |-------------------------------------------------------------------------- 134 | | Use Route Middleware 135 | |-------------------------------------------------------------------------- 136 | | 137 | | Drips are enabled via route middleware instead of global middleware. 138 | | 139 | | Default: false (bool) 140 | | 141 | */ 142 | 'use-route-middleware' => false, 143 | 144 | ]; 145 | ``` 146 | 147 | ___Only publish the config file if you need to customize it___: 148 | ```sh 149 | php artisan caffeine:publish --config 150 | ``` 151 | 152 | ## Usage 153 | That was it! It will apply itself automatically where it finds a form with a 154 | `_token` field, or a meta tag named "csrf-token", while pages are open in 155 | browsers. 156 | 157 | ### Prevent Caffeination 158 | There are two methods to prevent Caffeine for Laravel from dripping to keep the 159 | session alive: disabling it in Blade using the meta tag method, or enabling 160 | route-middleware mode, and then only enabling it on routes or route groups. 161 | 162 | #### Meta Tag Method 163 | If you would like to prevent a certain page from caffeinating your application, 164 | then add the following meta tag: 165 | ```php 166 | 167 | ``` 168 | 169 | #### Route Middleware Method 170 | To enable this mode, you need to publish the configuration file (see the 171 | configuration section above) and then set `use-route-middleware` to `true`. This 172 | will disable the default global middleware mode (which applies it to any page 173 | that has the CSRF token in it across your entire application). Now you need to 174 | selectively enable Caffeine on a given route or route group using route 175 | middleware: 176 | 177 | ```php 178 | Route::any('test', 'TestController@test')->middleware('caffeinated'); 179 | 180 | Route::group(['middleware' => ['caffeinated']], function () { 181 | Route::any('test', 'TestController@test'); 182 | }) 183 | ``` 184 | 185 | You can still use the route middleware method and apply it globally to all 186 | routes by editing `app/Http/Kernel.php` and adding it to the `web` middleware 187 | group. Although you should only use this option if you have a very specific use- 188 | case that prevents you from utilizing the default global middleware option. 189 | 190 | __This will only have effect if the page includes a form. If not, the page will 191 | not caffeinate your application anyway.__ 192 | 193 | # The Fine Print 194 | ## Commitment to Quality 195 | During package development I try as best as possible to embrace good design and 196 | development practices to try to ensure that this package is as good as it can 197 | be. My checklist for package development includes: 198 | 199 | - ✅ Achieve as close to 100% code coverage as possible using unit tests. 200 | - ✅ Eliminate any issues identified by SensioLabs Insight and Scrutinizer. 201 | - ✅ Be fully PSR1, PSR2, and PSR4 compliant. 202 | - ✅ Include comprehensive documentation in README.md. 203 | - ✅ Provide an up-to-date CHANGELOG.md which adheres to the format outlined 204 | at . 205 | - ✅ Have no PHPMD or PHPCS warnings throughout all code. 206 | 207 | ## Contributing 208 | Please observe and respect all aspects of the included Code of Conduct 209 | . 210 | 211 | ### Reporting Issues 212 | When reporting issues, please fill out the included template as completely as 213 | possible. Incomplete issues may be ignored or closed if there is not enough 214 | information included to be actionable. 215 | 216 | ### Submitting Pull Requests 217 | Please review the Contribution Guidelines . 218 | Only PRs that meet all criterium will be accepted. 219 | 220 | ## ❤️ Open-Source Software - Give ⭐️ 221 | We have included the awesome `symfony/thanks` composer package as a dev 222 | dependency. Let your OS package maintainers know you appreciate them by starring 223 | the packages you use. Simply run `composer thanks` after installing this 224 | package. (And not to worry, since it's a dev-dependency it won't be installed in 225 | your live environment.) 226 | -------------------------------------------------------------------------------- /caffeine.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikebronner/laravel-caffeine/79a3cb163f1d3c79a004725cbd9ee17ed9e06415/caffeine.jpg -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "genealabs/laravel-caffeine", 3 | "description": "Keeping Your Laravel Forms Awake", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Mike Bronner", 8 | "email": "hello@genealabs.com" 9 | } 10 | ], 11 | "require": { 12 | "illuminate/routing": "^10.0|^11.0|^12.0", 13 | "illuminate/support": "^10.0|^11.0|^12.0" 14 | }, 15 | "require-dev": { 16 | "orchestra/testbench-browser-kit": "^10.0", 17 | "orchestra/testbench-dusk": "^10.0", 18 | "orchestra/testbench": "^10.0", 19 | "phpmd/phpmd": "^2.13", 20 | "phpunit/phpunit": "^11.5.3" 21 | }, 22 | "autoload": { 23 | "psr-4": { 24 | "GeneaLabs\\LaravelCaffeine\\": "src/" 25 | } 26 | }, 27 | "autoload-dev": { 28 | "psr-4": { 29 | "GeneaLabs\\LaravelCaffeine\\Tests\\": "tests/" 30 | } 31 | }, 32 | "config": { 33 | "optimize-autoloader": true, 34 | "preferred-install": "dist", 35 | "sort-packages": true 36 | }, 37 | "extra": { 38 | "laravel": { 39 | "providers": [ 40 | "GeneaLabs\\LaravelCaffeine\\Providers\\Service" 41 | ] 42 | } 43 | }, 44 | "minimum-stability": "dev", 45 | "prefer-stable": true 46 | } 47 | -------------------------------------------------------------------------------- /config/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikebronner/laravel-caffeine/79a3cb163f1d3c79a004725cbd9ee17ed9e06415/config/.gitkeep -------------------------------------------------------------------------------- /config/genealabs-laravel-caffeine.php: -------------------------------------------------------------------------------- 1 | 300000, 18 | 19 | /* 20 | |-------------------------------------------------------------------------- 21 | | Domain 22 | |-------------------------------------------------------------------------- 23 | | 24 | | You may optionally configure a separate domain that you are running 25 | | Caffeine for Laravel on. This may be of interest if you have a 26 | | monitoring service that queries other apps. Setting this to 27 | | null will use the domain of the current application. 28 | | 29 | | Default: null (null|string) 30 | | 31 | */ 32 | 'domain' => null, 33 | 34 | /* 35 | |-------------------------------------------------------------------------- 36 | | Drip Endpoint URL 37 | |-------------------------------------------------------------------------- 38 | | 39 | | Sometimes you may wish to white-label your app and not expose the AJAX 40 | | request URLs as belonging to this package. To achieve that you can 41 | | rename the URL used for dripping caffeine into your application. 42 | | 43 | | Default: 'genealabs/laravel-caffeine/drip' (string) 44 | | 45 | */ 46 | 'route' => 'genealabs/laravel-caffeine/drip', // Customizable end-point URL 47 | 48 | /* 49 | |-------------------------------------------------------------------------- 50 | | Checking for Lapsed Drips 51 | |-------------------------------------------------------------------------- 52 | | 53 | | If the browser is put to sleep on (for example on mobile devices or 54 | | laptops), it will still cause an error when trying to submit the 55 | | form. To avoid this, we force-reload the form 2 minutes prior 56 | | to session time-out or later. Setting this setting to 0 57 | | will disable this check if you don't want to use it. 58 | | 59 | | Default: 2000 (int) 60 | | 61 | */ 62 | 'outdated-drip-check-interval' => 2000, 63 | 64 | /* 65 | |-------------------------------------------------------------------------- 66 | | Use Route Middleware 67 | |-------------------------------------------------------------------------- 68 | | 69 | | Drips are enabled via route middleware instead of global middleware. 70 | | 71 | | Default: false (bool) 72 | | 73 | */ 74 | 'use-route-middleware' => false, 75 | 76 | ]; 77 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | # For more information: https://laravel.com/docs/sail 2 | version: '3' 3 | services: 4 | laravel.test: 5 | image: ghcr.io/mikebronner/sail/php-8.2:latest 6 | extra_hosts: 7 | - 'host.docker.internal:host-gateway' 8 | ports: 9 | - '${APP_PORT:-80}:80' 10 | - '${VITE_PORT:-5173}:${VITE_PORT:-5173}' 11 | environment: 12 | WWWUSER: '${WWWUSER:-1000}' 13 | LARAVEL_SAIL: 1 14 | XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}' 15 | XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}' 16 | volumes: 17 | - '.:/var/www/html' 18 | networks: 19 | - sail 20 | 21 | networks: 22 | sail: 23 | driver: bridge 24 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | ./tests/Feature 12 | 13 | 14 | ./tests/Unit 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ./src 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /resources/views/script.blade.php: -------------------------------------------------------------------------------- 1 | @if (function_exists('csp_nonce')) 2 | 49 | -------------------------------------------------------------------------------- /routes/web.php: -------------------------------------------------------------------------------- 1 | middleware('web'); 8 | -------------------------------------------------------------------------------- /src/Console/Commands/Publish.php: -------------------------------------------------------------------------------- 1 | option('config')) { 15 | $this->call('vendor:publish', [ 16 | '--provider' => Service::class, 17 | '--tag' => ['config'], 18 | '--force' => true, 19 | ]); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Dripper.php: -------------------------------------------------------------------------------- 1 | with([ 13 | "ageCheckInterval" => $this->getAgeCheckInterval(), 14 | "ageThreshold" => $this->getAgeThreshold(), 15 | "interval" => $this->getInterval(), 16 | "url" => $this->getUrl(), 17 | ]); 18 | } 19 | 20 | protected function getAgeCheckInterval(): int 21 | { 22 | return config("genealabs-laravel-caffeine.outdated-drip-check-interval", 2000); 23 | } 24 | 25 | protected function getAgeThreshold(): int 26 | { 27 | return (config("session.lifetime", 32) - 2) * 60000; 28 | } 29 | 30 | protected function getInterval(): int 31 | { 32 | return config("genealabs-laravel-caffeine.drip-interval", 300000); 33 | } 34 | 35 | protected function getUrl(): string 36 | { 37 | return trim(config("genealabs-laravel-caffeine.domain") ?? url("/"), "/") 38 | . "/" 39 | . trim( 40 | config("genealabs-laravel-caffeine.route", "genealabs/laravel-caffeine/drip"), 41 | "/", 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Http/Controllers/Drip.php: -------------------------------------------------------------------------------- 1 | getContent(); 14 | 15 | if (! is_string($content) || strlen(trim($content)) === 0) { 16 | return $response; 17 | } 18 | 19 | $shouldDripRegexp = $this->makeRegex([ 20 | 'makeRegex([ 32 | "makeRegex([ 35 | ")\s*\z/', "{$dripper->getHtml()}", $content); 46 | 47 | if (! preg_match_all('/(<\/html>)\s*\z/', $content, $matches)) { 48 | $content .= $dripper->getHtml(); 49 | } 50 | 51 | $original = $response->original; 52 | $response->setContent($content); 53 | $response->original = $original; 54 | 55 | return $response; 56 | } 57 | 58 | protected function makeRegex(array $regexp) : string 59 | { 60 | return '/' . implode('', $regexp) . '/'; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Providers/Service.php: -------------------------------------------------------------------------------- 1 | loadRoutesFrom(__DIR__.'/../../routes/web.php'); 14 | 15 | if (config("app.env") === 'internaltesting') { 16 | $this->loadRoutesFrom(__DIR__.'/../../tests/routes/web.php'); 17 | } 18 | 19 | $configPath = __DIR__ . '/../../config/genealabs-laravel-caffeine.php'; 20 | $this->mergeConfigFrom($configPath, 'genealabs-laravel-caffeine'); 21 | $this->loadViewsFrom( 22 | __DIR__ . '/../../resources/views', 23 | 'genealabs-laravel-caffeine' 24 | ); 25 | 26 | if (config("app.env") === 'internaltesting') { 27 | $this->loadViewsFrom( 28 | __DIR__ . '/../../tests/resources/views', 29 | 'genealabs-laravel-caffeine' 30 | ); 31 | } 32 | 33 | $this->publishes([ 34 | $configPath => config_path('genealabs-laravel-caffeine.php') 35 | ], 'config'); 36 | 37 | $this->commands(Publish::class); 38 | $this->mergeConfigFrom(__DIR__ . '/../../config/genealabs-laravel-caffeine.php', 'genealabs-laravel-caffeine'); 39 | 40 | if ($this->shouldRegisterGlobalMiddleware()) { 41 | app(Kernel::class)->pushMiddleware('\\' . LaravelCaffeineDripMiddleware::class); 42 | } 43 | 44 | if ($this->shouldRegisterRouteMiddleware()) { 45 | app('router')->aliasMiddleware( 46 | 'caffeinated', 47 | '\\' . LaravelCaffeineDripMiddleware::class 48 | ); 49 | } 50 | } 51 | 52 | protected function shouldRegisterGlobalMiddleware() : bool 53 | { 54 | return (! request()->ajax() 55 | && ! $this->shouldRegisterRouteMiddleware() 56 | && (php_sapi_name() === 'fpm-fcgi' 57 | || php_sapi_name() === 'cgi-fcgi' 58 | || php_sapi_name() === 'apache2handler' 59 | || php_sapi_name() === 'litespeed' 60 | || php_sapi_name() === 'cli-server' 61 | || config("app.env") === 'internaltesting')); 62 | } 63 | 64 | protected function shouldRegisterRouteMiddleware() : bool 65 | { 66 | return (bool) config('genealabs-laravel-caffeine.use-route-middleware'); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /tests/CreatesApplication.php: -------------------------------------------------------------------------------- 1 | app = $this->createApplication(); 12 | } 13 | 14 | /** 15 | * @SuppressWarnings(PHPMD.UnusedFormalParameter) 16 | */ 17 | protected function getPackageProviders($app) 18 | { 19 | return [LaravelCaffeineService::class]; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/Feature/CaffeineTest.php: -------------------------------------------------------------------------------- 1 | get($dripRoute); 13 | 14 | $response->seeStatusCode(204); 15 | } 16 | 17 | public function testMiddlewareInjectsDripScript() 18 | { 19 | $expectedResult = file_get_contents(__DIR__ . '/../Fixtures/partial_script.txt'); 20 | 21 | $response = $this->get(route('genealabs-laravel-caffeine.tests.form')); 22 | 23 | $response->see($expectedResult); 24 | $response->assertViewHas('foo'); 25 | } 26 | 27 | public function testSuccessfulDrip() 28 | { 29 | $dripRoute = config('genealabs-laravel-caffeine.route', 'genealabs/laravel-caffeine/drip'); 30 | $html = $this->get(route('genealabs-laravel-caffeine.tests.form')) 31 | ->response 32 | ->getContent(); 33 | $matches = []; 34 | preg_match('//', $html, $matches); 35 | $csrfToken = $matches[1]; 36 | 37 | $response = $this->get($dripRoute, [ 38 | '_token' => $csrfToken, 39 | ]); 40 | 41 | $response->seeStatusCode(204); 42 | } 43 | 44 | public function testExpiredDrip() 45 | { 46 | $dripRoute = config( 47 | 'genealabs-laravel-caffeine.drip-interval', 48 | 'genealabs/laravel-caffeine/drip' 49 | ); 50 | $html = $this 51 | ->get(route('genealabs-laravel-caffeine.tests.form')) 52 | ->response 53 | ->getContent(); 54 | $matches = []; 55 | preg_match( 56 | '//', 57 | $html, 58 | $matches 59 | ); 60 | $csrfToken = $matches[1]; 61 | 62 | app('session')->flush(); 63 | $response = $this->get($dripRoute, [ 64 | '_token' => $csrfToken, 65 | ]); 66 | 67 | $response->seeStatusCode(404); 68 | } 69 | 70 | public function testDisabledCaffeination() 71 | { 72 | $html = $this 73 | ->get(route('genealabs-laravel-caffeine.tests.disabled-page')) 74 | ->response 75 | ->getContent(); 76 | 77 | $isDisabled = (bool) preg_match( 78 | '//', 79 | $html 80 | ); 81 | $hasDripper = (bool) preg_match( 82 | '/\var caffeineSendDrip\b/', 83 | $html 84 | ); 85 | 86 | $this->assertTrue($isDisabled); 87 | $this->assertFalse($hasDripper); 88 | } 89 | 90 | public function testNonStringReturnContent() 91 | { 92 | $response = $this->get(route('genealabs-laravel-caffeine.tests.null-response')); 93 | 94 | $response->dontSee('var caffeineSendDrip'); 95 | } 96 | 97 | public function testRouteMiddleware() 98 | { 99 | app('router')->aliasMiddleware( 100 | 'caffeinated', 101 | '\\' . LaravelCaffeineDripMiddleware::class 102 | ); 103 | 104 | $response = $this 105 | ->get(route('genealabs-laravel-caffeine.tests.route-middleware')); 106 | 107 | $response->see('var caffeineSendDrip'); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /tests/FeatureTestCase.php: -------------------------------------------------------------------------------- 1 | 2 | var lastCheck = new Date(); 3 | var caffeineSendDrip = function () { 4 | var ajax = window.XMLHttpRequest 5 | ? new XMLHttpRequest 6 | : new ActiveXObject('Microsoft.XMLHTTP'); 7 | 8 | ajax.onreadystatechange = function () { 9 | if (ajax.readyState === 4 && ajax.status === 204) { 10 | lastCheck = new Date(); 11 | } 12 | }; 13 | 14 | ajax.open('GET', 'http://127.0.0.1/genealabs/laravel-caffeine/drip'); 15 | ajax.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); 16 | ajax.send(); 17 | }; 18 | 19 | setInterval(function () { 20 | caffeineSendDrip(); 21 | }, 50000); 22 | 23 | if (2000 > 0) { 24 | setInterval( 25 | function () { 26 | if (new Date() - lastCheck >= 7082000) { 27 | location.reload(true); 28 | setTimeout( 29 | function () { 30 | location.reload(); 31 | }, 32 | Math.max(0, 2000 - 500), 33 | ); 34 | } 35 | }, 36 | 2000, 37 | ); 38 | } 39 | 40 | -------------------------------------------------------------------------------- /tests/Fixtures/partial_script.txt: -------------------------------------------------------------------------------- 1 | 45 | -------------------------------------------------------------------------------- /tests/Fixtures/unexpired_script.txt: -------------------------------------------------------------------------------- 1 | 45 | -------------------------------------------------------------------------------- /tests/Http/Controllers/Test.php: -------------------------------------------------------------------------------- 1 | set('session.lifetime', 1); 11 | config()->set('genealabs-laravel-caffeine.drip-interval', 50000); 12 | 13 | return view('genealabs-laravel-caffeine::tests.form')->with('foo'); 14 | } 15 | 16 | public function disabledPage() : View 17 | { 18 | return view('genealabs-laravel-caffeine::tests.disabled'); 19 | } 20 | 21 | public function nullResponse() 22 | { 23 | return null; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/Unit/Console/Commands/PublishTest.php: -------------------------------------------------------------------------------- 1 | artisan('caffeine:publish', ['--config' => true]); 10 | 11 | $this->assertFileExists(base_path('config/genealabs-laravel-caffeine.php')); 12 | } 13 | 14 | public function testConfigFileContainsCorrectSettings() 15 | { 16 | $settings = file_get_contents(base_path('config/genealabs-laravel-caffeine.php')); 17 | 18 | $this->assertStringContainsString("'drip-interval' => 300000,", $settings); 19 | $this->assertStringContainsString("'domain' => null,", $settings); 20 | $this->assertStringContainsString("'route' => 'genealabs/laravel-caffeine/drip',", $settings); 21 | $this->assertStringContainsString("'outdated-drip-check-interval' => 2000,", $settings); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/Unit/DripperTest.php: -------------------------------------------------------------------------------- 1 | getHtml(); 18 | 19 | $this->assertEquals($expectedResult, $actualResult); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/UnitTestCase.php: -------------------------------------------------------------------------------- 1 | 5 | @endsection 6 | 7 | @section ('content') 8 |
9 | {{ csrf_field() }} 10 | 11 | 12 |
13 | @endsection 14 | -------------------------------------------------------------------------------- /tests/resources/views/tests/form.blade.php: -------------------------------------------------------------------------------- 1 | @extends('genealabs-laravel-caffeine::tests.layout') 2 | 3 | @section('content') 4 |

Test Form

5 |
6 | {{ csrf_field() }} 7 | 8 | 9 |
10 | @endsection 11 | -------------------------------------------------------------------------------- /tests/resources/views/tests/layout.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | @yield ('meta') 9 | 10 | 11 | 12 | 13 | {{ config('app.name', 'Laravel') }} 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | @yield ('content') 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /tests/routes/web.php: -------------------------------------------------------------------------------- 1 | ['web'], 5 | 'as' => 'genealabs-laravel-caffeine.', 6 | 'prefix' => 'tests', 7 | 'namespace' => 'GeneaLabs\LaravelCaffeine\Tests\Http\Controllers', 8 | ], function () { 9 | Route::any('form', 'Test@drippedForm') 10 | ->name('tests.form'); 11 | Route::any('dripped-form', 'Test@drippedForm'); 12 | Route::any('expiring-form', 'Test@expiredForm'); 13 | Route::any('disabled-page', 'Test@disabledPage') 14 | ->name('tests.disabled-page'); 15 | Route::any('null-response', 'Test@nullResponse') 16 | ->name('tests.null-response'); 17 | Route::any('route-middleware', 'Test@drippedForm') 18 | ->name('tests.route-middleware') 19 | ->middleware('caffeinated'); 20 | }); 21 | --------------------------------------------------------------------------------