How to detect browser in Elm - elm

How do I detect the browser from Elm?
Specifically I want to be able to tell if the web app is running on a tablet (Safari on iPad, etc.) or not.

You can use Html.programWithFlags to pass information from Javascript to Elm on initialization.
Assuming you can infer browser from user agent, you could do something like this:
type alias Flags =
{ userAgent : String }
Your init would look like this:
init : Flags -> ( Model, Cmd Msg )
init flags =
...
main =
programWithFlags { init = init, ... }
And from Javascript, you would pass the flags in like this:
var app = Elm.Main.fullscreen({
userAgent: navigator.userAgent
});
Side note: User agent may not be enough to fully detect browser. You can see this StackOverflow answer which provides more reliable detection. Either way, the end result is that you would send some kind of flag along to the Elm app on init.
More info on Flags can be found here.

You can use elm-vendor package.
http://package.elm-lang.org/packages/coreytrampe/elm-vendor/latest

Related

Can we actually send out mails during semi-automatic testing?

We are using unit / integration tests during Shopware 6 development.
One technique we use is to disable database transaction behaviour to see the results for example of fixtures in the admin panel, for an easier debugging / understanding:
trait IntegrationTestBehaviour
{
use KernelTestBehaviour;
// use DatabaseTransactionBehaviour;
use FilesystemBehaviour;
use CacheTestBehaviour;
use BasicTestDataBehaviour;
use SessionTestBehaviour;
use RequestStackTestBehaviour;
}
Similar to this it would be helpful to send out actual emails during some tests (only for development, not in the CI and so on).
It is already possible to automatically test emails like this:
$eventDidRun = false;
$listenerClosure = function (MailSentEvent $event) use (&$eventDidRun): void {
$eventDidRun = true;
};
$this->addEventListener($dispatcher, MailSentEvent::class, $listenerClosure);
// do something that sends an email
static::assertTrue($eventDidRun, 'The mail.sent Event did not run');
But sometimes we want to manually see the actual email.
The .env.test already contains a valid mailer URL:
MAILER_URL=smtp://x:y#smtp.mailtrap.io:2525?encryption=tls&auth_mode=login
But still no mails get send during the test.
While I guess that this is fully intentional, is there some method to workaround the blockage of getting mails sent during testing?
The reason is the MAILER_URL variable is pre-set to null://localhost in the phpunit.xml.dist of the platform repository:
<server name="MAILER_URL" value="null://localhost"/>
You could set the MAILER_URL environment variable yourself before the tests of the class are executed:
/**
* #beforeClass
*/
public static function setMailerUrl(): void
{
$_SERVER['MAILER_URL'] = 'smtp://x:y#smtp.mailtrap.io:2525?encryption=tls&auth_mode=login';
}

system_cpu_usage is Nan when compiled in native

In my quarkus application i'm using micrometer to retrieve metrics (like in this guide : https://quarkus.io/guides/micrometer).
In JVM mode everything works fine, but in native mode system_cpu_usage is "Nan".
I tried bumping micrometer to 1.8.4 and adding :
{
"name":"com.sun.management.OperatingSystemMXBean", "allPublicMethods": true
},
to my reflect-config.json but no luck. I also tried generating the reflect-config (and other native configuration files) with the graalvm tracing agent but still no luck.
This may be a bug.
Micrometer is looking for a few known implementations of the MXBean:
https://github.com/micrometer-metrics/micrometer/blob/b087856355667abf9bf2386265edef8642e0e077/micrometer-core/src/main/java/io/micrometer/core/instrument/binder/system/ProcessorMetrics.java#L55
private static final List<String> OPERATING_SYSTEM_BEAN_CLASS_NAMES = Arrays.asList(
"com.ibm.lang.management.OperatingSystemMXBean", // J9
"com.sun.management.OperatingSystemMXBean" // HotSpot
);
so that it can find the methods that it should be invoking...
https://github.com/micrometer-metrics/micrometer/blob/b087856355667abf9bf2386265edef8642e0e077/micrometer-core/src/main/java/io/micrometer/core/instrument/binder/system/ProcessorMetrics.java#L80
this.operatingSystemBean = ManagementFactory.getOperatingSystemMXBean();
this.operatingSystemBeanClass = getFirstClassFound(OPERATING_SYSTEM_BEAN_CLASS_NAMES);
Method getCpuLoad = detectMethod("getCpuLoad");
this.systemCpuUsage = getCpuLoad != null ? getCpuLoad : detectMethod("getSystemCpuLoad");
this.processCpuUsage = detectMethod("getProcessCpuLoad");
(Note specifically "getFirstClassFound", which is constrained against the first list).
Speculation on my part, but I suspect Graal is returning a different type, which is possible from here:
https://github.com/oracle/graal/blob/6ba65dad76a4f54fa59e1ed2a62dedd3afe39928/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/management/ManagementSupport.java#L166
would take some digging to know which, but I would open an issue with Micrometer so we can sort it out.

How can I get window.location.href in Elm?

I have an index.html which contains my Elm app. The Elm app uses various GETs to an API served by the same server as the one that serves the index.html.
Rather than hardcode the URLs in my Elm code for the GETs, e.g.:
url =
"http://localhost:8080/api/tasks"
is there a function which returns the value of window.location.href?
I'd like to do something like:
url =
getHref() ++ "/api/tasks"
In this way, if I move my server to somewhere else I will not need to update all the urls in my Elm code.
Whilst the above answers your question, I think there is a more straightforward solution to the problem:
If the application code is being served from the same server (URL) as the API you want to access you don't need to specify the server - just the root relative path for your api i.e. you can make requests to /api/tasks from your elm code and the browser will sort out the rest for you.
This is how I addressed the problem in my deployed code.
There is elm-history package with the location function for this, but it's deprecated and doesn't exist for 0.18 version.
Then you might want to use elm-navigation package and explicitly store the current location in your model.
Please have a look at this example. A program with navigation can be created via:
Navigation.program UrlChange
{ init = init
, view = view
, update = update
, subscriptions = (\_ -> Sub.none)
}
UrlChange here is a type of message, which triggers on every url change, so you can process it and set the current location:
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
UrlChange location ->
( { model | location = location }
, Cmd.none
)
And then purely get the location.href wherever the model is accessible.
In the provided application, this place is view: viewLocation model.location
In your application, it's, for example, something like this:
url model =
model.location.href ++ "/api/tasks"
Use URL Builder to link to anoter page on your site
There's no need to specify the base url:
import Url.Builder exposing (absolute)
url = absolute [ "api", "tasks" ] []
-- results in "http://localhost:8080/api/tasks"
-- if working in your developer environment
-- the URL will automatically change in production
-- to the correct URL assuming you don't have any crazy set ups
And you definitely will not need to worry if your server URL changes. So you can easily switch from a development to production/staging environments without any additional configuration.

How to add modernizr build so that I can properly check Modernizr.capture? (currently always undefined)

I need to check if the user's device can input from a camera on my site. To do this I am attempting to use modernizr. I have followed the steps/example code provided on their site but when I test the capture attribute, I always get undefined, regardless of if I am on a device that supports capture.
Steps I followed:
I browsed for the input[capture] attribute and added it to the build
I copied the demo code to check this feature and added it to my project
I downloaded the build, added the js file to my project, and included the appropriate reference in my page
However after all of this, when inspecting Modernizr.capture in the chrome inspector, it always shows up as undefined.
My basic check function is as follows:
$scope.hasCamera = function() {
if (Modernizr.capture) {
// supported
return true;
} else {
// not-supported
return false;
}
}
This is my first time using Modernizr. Am I missing a step or doing something incorrectly? I also installed modernizr using npm install and tried adding the reference to a json config file from the command line.
Alternatively, how might I check if my device has a camera?
Thank you very much for your time. Please let me know if I am being unclear or if you need any additional information from me.
A few things
while photos are helpful, actual code hosted in a public website (either your own project, or on something like jsbin.com) is 10x as useful. As a result, I am not sure why it is coming back as undefined.
The actual capture detect is quite simple. It all comes down to this
var capture = 'capture' in document.createElement('input')`
Your code is a lot more complicated than it needs to be. Lets break it down. You trying to set $scope.hasCamera to equal the result of Modernizr.capture, and you are using a function to check the value of Modernizr.capture, and if it is true, return true. If it is false, return false. There is a fair bit of duplicated logic, so we can break it down from the inside out.
Firstly, your testing for a true/false value, and then returning the same value. That means you could simplify the code by just returning the value of Modernizr.capture
$scope.hasCamera = function() {
return Modernizr.capture
}
While Modernizr will always be giving you a boolean value (when it is functioning - without seeing your actual code I can't say why it is coming back as undefined), if you are unsure of the value you can add !! before it to coerce it into a boolean. In your case, it would make undefined into false
$scope.hasCamera = function() {
return !!Modernizr.capture
}
At this point, you can see that we are setting up a function just to return a static value. That means we can just set assign that static value directly to the variable rather than setting up a function to do that
$scope.hasCamera = !!Modernizr.capture
Now, the final thing you may be able to do something better is if you are only using Modernizr for this one feature. Since it is such a simple feature detection, it is overkill to be using all of Modernizr.
$scope.hasCamera = 'capture' in document.createElement('input')`

How can I interact with the user inside a CasperJS/PhantomJS script?

Imagine a script like
system = require "system"
system.stdout.write "What's your name? "
name = system.stdin.readLine()
system.stdout.writeLine "Hello, #{name}"
To be run via
casperjs name.coffee
I'd like to be able to interact with the user in the terminal used to run the script, but I get stuck in the readLine() call.
As GarethOwen pointed out, it is indeed possible.
Here is a very basic CasperJS implementation of the Unix command cat:
var system = require('system'),
casper = require('casper').create();
while (!system.stdin.atEnd()) {
var line = system.stdin.readLine();
casper.log(line);
}
casper.exit();
Note that this module is mostly implemented in C++:
https://github.com/ariya/phantomjs/blob/master/src/system.h
And that stdin / stdout / stderr are instances of the PhantomJs class File :
https://github.com/ariya/phantomjs/blob/master/src/filesystem.h
According to the documentation, phantomJS can communicate with standard input. See this example:
https://github.com/ariya/phantomjs/blob/master/examples/stdin-stdout-stderr.js
Documentation regarding inter-process communication is here:
https://github.com/ariya/phantomjs/wiki/Inter-Process-Communication
But I've never tried it myself.