Access --dart-define environment variables inside index.html - flutter

Is there any way to access Environment Variables defined by the --dart-define command inside the index.html file of Flutter Web?
I currently can access them inside iOS and Android native files but have not found a way to do so inside the html file

Access to the environment declarations (this is the most correct name, also used in the doc of the String.fromEnvironment() method; see also
dart-sdk issue #42136 - Clarify usage of -D/environment variables/environment declarations), is also possible from the javascript code.
There are two details to keep in mind:
String.fromEnvironment() can only be invoked with const (also implicit, in const context) and never with "new".
In Flutter/web, the main() method is not executed immediately upon loading the main.dart.js script, so it is not sufficient to place the js script (which reads the variable declared in dart) immediately after main.dart.js. It is therefore necessary to signal in some way to the js code when the dart code has been executed. To solve this problem, I resort to a custom DOM event. If there are better solutions, I invite you to report them.
Example:
main.dart
import 'package:flutter/material.dart';
import 'dart:js' as js;
import 'dart:html' as html;
void main() {
//To expone the dart variable to global js code
js.context["my_dart_var"] = const String.fromEnvironment("my_dart_var");
//Custom DOM event to signal to js the execution of the dart code
html.document.dispatchEvent(html.CustomEvent("dart_loaded"));
runApp(MyApp());
}
class MyApp extends StatelessWidget {
//...
}
In index.html:
<script src="main.dart.js" type="application/javascript"></script>
<script>
//Here my_dart_var is undefined
console.log(`my_dart_var: ${window.my_dart_var}`);
document.addEventListener("dart_loaded", function (){
//Here my_dart_var is defined
console.log("dart_loaded event");
console.log(`my_dart_var: ${window.my_dart_var}`);
});
</script>

Related

How to dynamically import a json file

I'm trying to import a JSON file on my Vite app, whose paths are dynamically generated. So the import path for this JSON includes variables.
I know it's possible to do it with require, but I'm working with Svelte, and I cant use requires.
You can use a dynamic import() statement for that. This will return a promise, which has to be awaited, though. E.g.
<script lang="ts">
import meta from './meta.json';
const filePromise = import(/* #vite-ignore */ `./${meta.file}.json`);
</script>
{#await filePromise then file}
{file.property}
{/await}
There are some limitations to dynamic imports in Vite so the application can be built properly. The #vite-ignore comment silences a warning output about these limitations.

Mock JS object in tests on browser platform

I have this simplified dart file using dart:js:
(dataLayer is used for Google tags, if that's any help)
#JS()
import 'package:js/js.dart';
#JS('dataLayer.push')
external void _push(data);
class Manager {
void pushEvent(String event) {
_push(event);
}
}
On the web, it runs correctly and the dataLayer object is being created in a script in the web/index.html file.
I am trying to write a test about it. I would like to verify dataLayer.push is being called with the correct parameters.
I run my test with the command
flutter test --platform chrome
But I get this error:
TypeError: Cannot read properties of undefined (reading 'push')
Is it possible to create a dummy dataLayer variable (and maybe have the hand on it to record the calls to the method .push())? If yes, how?
Here is my attempt:
#TestOn('browser')
import 'package:flutter_test/flutter_test.dart';
import 'package:js/js.dart';
import 'my_project/my_file.dart';
class _DataLayer {
void push(dynamic data) {}
}
#JS('dataLayer')
final dataLayer = _DataLayer();
void main() {
test('It should push the event', () {
Manager().pushEvent('myEvent');
});
}
A way to do it would be to load and use a custom HTML file during the tests where you can include a script to create the js variables you need.
Follow the instructions of the package test.
If your test file name is folder/my_test.dart, then you can create a html file named (folder/my_test.html):
<!doctype html>
<html>
<head>
<title>Custom HTML file title</title>
<link rel="x-dart-test" href="my_test.dart">
<script src="packages/test/dart.js"></script>
<script>
window['dataLayer'] = [];
</script>
</head>
</html>
See this StackOverflow answer and this StackOverflow question.
and then you can run
dart test --platform chrome
However, this is only supported with dart test and not flutter test, see this issue. In it, they recommend writing an integration test instead.

Remove hash symbol ' # ' from Flutter web navigation

I want to create one simple web application with Flutter web but after I create some simple application with this document I faced with some issue on routing address it automatically add one hash '#' symbol to URL on the address bar, I want to know how I can remove this sign from URL, In fact, right now I see something like this on browser address-bar : http://[::1]:54587/#/register but I want to achieve to something like this http://[::1]:54587/register.
Configuring the URL strategy on the web
Include the flutter_web_plugins package and call the setUrlStrategy function before your app runs:
dependencies:
flutter_web_plugins:
sdk: flutter
Create a lib/configure_nonweb.dart file with the following code:
void configureApp() {
// No-op.
}
Create a lib/configure_web.dart file with the following code:
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
void configureApp() {
setUrlStrategy(PathUrlStrategy());
}
Open lib/main.dart and conditionally import configure_web.dart when the html package is available, or configure_nonweb.dart when it isn’t:
import 'package:flutter/material.dart';
import 'configure_nonweb.dart' if (dart.library.html) 'configure_web.dart';
void main() {
configureApp();
runApp(MyApp());
}
If your only concern is for routing, you can check out my answer here: https://stackoverflow.com/a/63042805/210417
Basically it just splits the current URL into a List and then removes the empty ones caused by the hash tag.

How to execute browser method inside protractor custom locator?

I want to execute browser method inside the protractor custom locator like:
import {browser} from 'protractor';
protractor.by.addLocator("demo",(selector: string) => {
browser.executeScript('my script')
});
This throws error like:
protractor_1 not defined.
Any help will be valuable.
Add on: Let me know, if we can use async /await inside custom locator.
The problem is CLEARLY NOT in the code you posted.
Somewhere you're using protractor_1, which is not defined. Look for it in your code
You have imported 'browser' but not the actual 'protractor'
import { browser, protractor } from 'protractor';
browser.executeScript cannot be executed in the context of the browser.
"#param {Function|string} script. A script to be run in the context of the browser.
Follow up the documentation: https://www.protractortest.org/#/api?view=ProtractorBy.prototype.addLocator

Why is ic-ajax not defined within certain functions in Ember CLI?

Forgive my ignorance, but I can't get ic-ajax working inside of certain
functions.
Specifically, I'd like to get a test like this working, but for Ember CLI:
e.g. http://coderberry.herokuapp.com/testing-your-ember-application#30
I can call ajax inside Ember.Object.Extend and outside of functions and object definitions, but not in modules, tests, or Ember.Route's model function.
Am I misunderstanding something or is there a misconfiguration in my app?
I've figured out that within functions I can do:
ajax = require('ic-ajax')['default'];
defineFixture = require('ic-ajax')['defineFixture'];
but I'm pretty sure import at the top of the file is supposed to work.
I'm experiencing this on Ember 0.40.0 (both in my existing app and a fresh app). See below for more specifics where I'm finding it undefined. Setting var ajax = icAjaxRaw outside of the functions does not work either. I'm at a bit of a loose end so any help you could give in this regard would be great.
users-test.js:
import ajax from 'ic-ajax';
import { raw as icAjaxRaw } from 'ic-ajax';
import { defineFixture as icAjaxDefineFixture } from 'ic-ajax';
debugger;
---> icAjaxDefineFixture IS defined here
module('Users', {
setup: function() {
App = startApp();
debugger;
icAjaxDefineFixture --> UNDEFINED
},
teardown: function() {
Ember.run(App, App.destroy);
}
});
test("Sign in", function() {
icAjaxDefineFixture --> UNDEFINED
expect(1);
visit('/users/sign-in').then(function() {
equal(find('form').length, 1, "Sign in page contains a form");
});
});
Brocfile.js (I don't think these are actually needed with the new ember-cli-ic-ajax addon):
app.import('vendor/ic-ajax/dist/named-amd/main.js', {
exports: {
'ic-ajax': [
'default',
'defineFixture',
'lookupFixture',
'raw',
'request',
]
}
});
Had the same problem. Turns out it is a Chrome debugger optimization issue, checkout this blog post http://johnkpaul.com/blog/2013/04/03/javascript-debugger-surprises/
While debugging, if you try to use a variable from a closure scope in the console, that wasn’t actually used in the source, you’ll be surprised by ReferenceErrors. This is because JavaScript debuggers optimize the hell out of your code and will remove variables from the Lexical Environment of a function if they are unused.
To play around in debugger, I've just typed ajax; inside of the closure and variable magically appeared.