So I have an app that can bring up push notifications in the browser. The problem is that I need to create a UI test using Laravel Dusk to test if the push notification actually appears in the user's browser.
In real applications, push notifications are triggered from the server side in real-time using Websocket. Because there is some code logic in the front end before popping the push notification, so I think using Mocking Event Fake is still not enough.
I have tried reading the official documentation on Laravel Dusk but unfortunately haven't found a solution.
With an example page like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button>Show Notification</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/push.js/1.0.8/push.min.js" integrity="sha512-eiqtDDb4GUVCSqOSOTz/s/eiU4B31GrdSb17aPAA4Lv/Cjc8o+hnDvuNkgXhSI5yHuDvYkuojMaQmrB5JB31XQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
const button = document.querySelector('button')
button.addEventListener('click', () => {
Push.create('Hello world!', {
body: 'Foo',
icon: 'https://example.com/images/icon.png',
link: 'https://example.com/',
timeout: 4000,
onClick: function () {
window.focus();
this.close();
},
})
})
</script>
</body>
</html>
The solution I might expect is something like this:
<?php
declare(strict_types=1);
namespace Tests\Browser;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;
class ExampleTest extends DuskTestCase
{
/**
* #test
*/
public function itShouldBeAbleToShowPushNotifications(): void
{
$this->browse(function (Browser $browser): void {
$browser
->visit('/')
->allowPushNotification() // The actual method doesn't exist, it's just an example I was hoping for
->click('button')
->assertSeePushNotification( // The actual method also doesn't exist
title: 'Hello world',
body: 'Foo',
icon: 'https://example.com/images/icon.png',
link: 'https://example.com/'
);
});
}
}
Is this possible? Or maybe there is a better alternative?
Related
I am testing botman chat. Followed documentation at https://botman.io/2.0/installation
Script open the chat widget at right bottom corner, but when I enter hello, it does not reply. Have tried multiple forums but not getting any solution.
Below is the script I am using
Installed botman
composer require botman/botman
Web Deriver
composer require botman/driver-web
index.php
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>COINS ChatBot</title>
<!-- <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/botman-web-widget#0/build/assets/css/chat.min.css"> -->
</head>
<body>
<script>
// Feel free to change the settings on your need
var botmanWidget = {
frameEndpoint: '/chat.html',
chatServer: 'chat.php',
title: 'ChatBot',
introMessage: 'Hi and welcome to our chatbot how can i help you ?',
placeholderText: 'Ask Me Something',
mainColor: '#F28240',
bubbleBackground: '#F28240',
aboutText: '',
aboutLink: '',
bubbleAvatarUrl: 'https://www.applozic.com/assets/resources/images/Chat-Bot-Icon#512px.svg'
};
</script>
<script src='https://cdn.jsdelivr.net/npm/botman-web-widget#0/build/js/widget.js'></script>
</body>
</html>
chat.html
<html>
<head>
<title>BotMan Widget</title>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/botman-web-widget#0/build/assets/css/chat.min.css">
</head>
<body>
<script id="botmanWidget" src='https://cdn.jsdelivr.net/npm/botman-web-widget#0/build/js/chat.js'></script>
</body>
</html>
chat.php
<?php
require_once 'vendor/autoload.php';
use BotMan\BotMan\BotMan;
use BotMan\BotMan\BotManFactory;
use BotMan\BotMan\Drivers\DriverManager;
$config = [
// Your driver-specific configuration
// "telegram" => [
// "token" => "TOKEN"
// ]
];
DriverManager::loadDriver(\BotMan\Drivers\Web\WebDriver::class);
$botman = BotManFactory::create($config);
// Give the bot something to listen for.
$botman->hears('hello', function (BotMan $bot) {
$bot->reply('Hello yourself.');
});
$botman->hears('Good Morning', function (BotMan $bot) {
$bot->reply('Hey John');
});
$botman->hears('what is the time in {city} located in {continent}' , function (BotMan $bot,$city,$continent) {
date_default_timezone_set("$continent/$city");
$reply = "The time in ".$city." ".$continent." is ".date("h:i:sa");
$bot->reply($reply);
});
$botman->fallback(function($bot) {
$bot->reply('Sorry, I did not understand these commands. Here is a list of commands I understand: ...');
});
// Start listening
$botman->listen();
?>
After checking I found may be issue with caching, I have installed APCU PHP Cache but still no luck.
I want when my socket connection in opened increase some value in my welcome.blade.php.
this is my EventClass:
// app/Events/TestEvent.php
class TestEvent implements ShouldBroadcast
{
...
public function broadcastOn()
{
return new Channel('test');
}
}
this is my route :
// routes/web.php
Route::get('/fire', function () {
event(new \App\Events\TestEvent());
return 'ok';
});
this is Echo configuration in bootstrap.js :
// resources/js/bootstrap.js
...
import Echo from "laravel-echo"
window.io = require('socket.io-client');
window.Echo = new Echo({
broadcaster: 'socket.io',
host: window.location.hostname + ':6001' // this is laravel-echo-server host
});
and this is my welcome.blade.php :
// resources/views/welcome.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Laravel</title>
</head>
<body>
<script src="{{ asset('/js/app.js') }}"></script>
<script>
Echo.channel('test')
.listen('TestEvent', e => {
console.log(e)
})
</script>
</body>
</html>
but when I fire the TestEvent my welcome page console is empty.
Since you defined the broadcastOn function, you need to make sure you are actually listening to that channel name. Currently you are listening to the event class name, which is the default channel name when you don't provide the broadcastOn function.
So, change your JavaScript code to listen to .test, and make sure to include the dot in front of the name!
All is well explained here: https://laravel.com/docs/8.x/broadcasting#broadcast-name
I am trying to create a chat application using Socket and using Swoole as backend. I successfully create a connection to server-client but the issue I am facing now is that whenever I close terminal WebSocket is unable to connect.
Server code:-
<?php
//Create the websocket server object
$websocket_server = new swoole_websocket_server("MY_IP", 3000);
// Register function of the opening connection event
$websocket_server->on('open', function($websocket_server, $request){
var_dump($request->fd, $request->get, $request->server);
$websocket_server->push($request->fd, "Hello welcome\n");
});
// Register function of the receiving message event
$websocket_server->on('message', function($websocket_server, $frame){
echo "Message : {$frame->data}\n";
$websocket_server->push($frame->fd, "Server : {$frame->data}");
});
// Register function of the close event
$websocket_server->on('close', function($websocket_server, $fd){
echo "client_{$fd} is closed\n";
});
// Start the server
$websocket_server->start();
Client side Code:-
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<script type="text/javascript">
var wsServer = 'ws://IP:3000';
var websocket = new WebSocket(wsServer);
websocket.onopen = function (evt) {
console.log("Connected to WebSocket server.");
};
websocket.onclose = function (evt) {
console.log("Disconnected");
};
websocket.onmessage = function (evt) {
console.log('Retrieved data from server: ' + evt.data);
};
websocket.onerror = function (evt, e) {
console.log('Error occured: ' + evt.data);
};
</script>
</body>
</html>
Everything is working fine the only issue is when we close terminal web socket id down.
I get the answer on Git. Please add below code in line
$websocket_server = new swoole_websocket_server("MY_IP", 3000);
$websocket_server->set([
'daemonize' => true,
]);
I get inconsistent duplicate inserts when running the following Laravel code: (I know I'm breaking all best practices, but this example code isolates the problem.)
App/routes/web.php:
<?php
use Illuminate\Support\Facades\DB; // NOTE: I am using the query builder, not a model
use Carbon\Carbon;
Route::get('formtest', function() {
return view('testing.index');
});
use Illuminate\Http\Request;
Route::post('formtest', function(Request $request) {
DB::table('pers2_testing_inserts')
->insert([
'data' => $request["test"],
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
]);
});
App/resources/views/testing/index.blade.php:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>TESTING</title>
</head>
<body>
<form id="form" action="" method="post" novalidate autocomplete="off" onsubmit="disableAndSubmit(event)">
<input type="text" name="test" id="text_box">
<input type="submit" id="submit_button">
</form>
<script type="text/javascript">
var text_box = document.getElementById('text_box');
var submit_button = document.getElementById('submit_button');
var form = document.getElementById('form');
function disableAndSubmit(e) {
submit_button.disabled = true;
if(text_box.value !== '') {
form.submit();
} else {
e.preventDefault();
submit_button.disabled = null;
}
}
</script>
</body>
</html>
My project is built in Laravel 5.4, PHP 7.1.7. I develop on a Mac, using vagrant as a virtual machine. My production server is a Windows Server 2008 R2 Standard Computer with XAMPP v3.2.2. The inconsistent duplicate inserting ONLY happens on the production server. Here is a screenshot of a few tests on the server.
I have inserts all over in my program, and any one of them can duplicate, and it's inconsistent. It shouldn't be that way. Is there something I should change in my XAMPP configuration? PHP configuration? Is there a workaround that I can implement that would prevent this from happening on the server?
try this:
<script type="text/javascript">
var text_box = document.getElementById('text_box');
var submit_button = document.getElementById('submit_button');
var form = document.getElementById('form');
function disableAndSubmit(e) {
e.preventDefault();
submit_button.disabled = true;
if(text_box.value !== '') {
form.submit();
return true;
} else {
submit_button.disabled = false;
return false;
}
}
</script>
I have a jquery ui button in a main page (index.php) which appears and works fine. In the main page I have a div <div id="cardarea"> which I use as a placeholder for dynamic content. The dynamic content is stored in another file (cardarea.php) and elements from this file is displayed dependent on the $_GET['key']; variable it gets from input forms in the main page.
Now the problem is that when I try to include the same jquery ui button (<settingsbtn>) in a part of the contents in the file cardarea.php, this does not display.
The javascript code and definitions are included in the header of index.php. I guess the button in the file cardarea.php cannot reach this information, or that there is an error in my javascript definitions. I've tried including the same javascript code and definitions also in the file cardarea.php, but with no effect.
I'm really quite at a loss of what is the problem here. I will include the javascript definitions, but I'm not sure what other code may be relevant to decifer this problem. Please let me know what additional information may be useful to find the problem, if applicable. Thanks.
Javascript:
$(function() {
$( "settingsbtn" ).button({
icons: {
primary: "ui-icon-triangle-1-s"
},
text: false
});
});
</script>
INDEX.PHP
<?php
include 'functions.php';
include 'incl_ajax.php';
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link href="css/amariffic.css" rel="stylesheet" type="text/css" />
<title>Test</title>
<link href="css/smoothness/jquery-ui-1.10.3.custom.css" rel="stylesheet">
<script src="js/jquery-1.9.1.js"></script>
<script src="js/jquery-ui-1.10.3.custom.js"></script>
<?php include 'snip_javascript.php'; // innholder både kode og css-link. ?>
</head>
<body class="body">
<settingsbtn></settingsbtn>
<a href="javascript:ajaxpage('_cardarea.php?key=5', '_cardarea');" class='nodecor'>Show</a>
<div id="_cardarea"></div>
</body>
</html>
CARDAREA.PHP
<?php
include 'functions.php';
$key = $_GET['key'];
if ($key == '5') {
echo '<div>';
echo 'Button: <settingsbtn> </settingsbtn>';
echo '</div>';
}
?>
You have to run the Javascript function you already wrote again after you complete the AJAX request.
Your function you have to run again:
$(function() {
$( "settingsbtn" ).button({
icons: {
primary: "ui-icon-triangle-1-s"
},
text: false
});
});
I actually ran that function in my Chrome console after the AJAX call, and the second button was correctly shown.
Just define in your javascript functions:
function initButtons(){
$( "settingsbtn" ).button({
icons: {
primary: "ui-icon-triangle-1-s"
},
text: false
});
}
Then overvrite your previously pasted javascript code with:
initButtons();
In the end, you have to add this function call to the end of your AJAX callback function:
initButtons();
put it just right after the instruction where you append the code you recieve from AJAX to the HTML.
EDIT: i looked at your code and i saw that you should put this function here:
function ajaxpage(url, containerid){
[...]
page_request.onreadystatechange=function(){
loadpage(page_request, containerid)
initButtons();
}
[..]
}
Perhaps delegate() is what you are looking for.