How to use a function from injected class in Aurelia? - aurelia

How to use a function from injected class in Aurelia? In my case, I'm calling a login() function (on the login page) and want to get the testMessage printed from Test Class. Unfortunately, I'm getting the following error in Chrome: "Uncaught TypeError: Cannot read property 'getTestMessage' of undefined".
test.js
export class Test {
constructor() {
this.testMessage = "test";
}
getTestMessage() {
return this.testMessage;
}
}
login.js
import {inject} from 'aurelia-framework';
import {Test} from 'test';
#inject(Test)
export class LogIn {
constructor(test) {
this.test = test;
}
login(){
console.log("login");
this.test.getTestMessage();
}
}

There is nothing wrong with your code. I copied it over to a test application and it worked. The issue most likely lies in the part you didn't reveal in your question: how you are calling the login method.
Login
In my test example, the view-model injecting test and subsequent HTML view is calling the login method using click.delegate. How are you calling the method?

Related

vue.js - class component - Update view when RxJs Observable change data

Disclaimer: I'm a beginner in using Vue.js, and being used to Angular I went the Class Component way. I know that not the proper Vue.js way, but this is a fun pet project, so I elected to do it in a unusual way in order to try new things.
I have a simple component, "MyForm", written using Typescript and the Class Component Decorator.
To simulate a service, I made a Typescript class "MyService", that contain methods simulating an API call using an RxJs Observable objects with a delay. The the service function update the data contained in another class "MyDataStore", which is then read by the component to update the view.
But when the observable returns and changes the Data in the Store, it does not update the displayed data (until the next clic on the button).
The component
<template>
<v-app>
<pre>
<v-btn #click="clickBouton()">Load</v-btn>
Form counter: {{counter}}
Service counter: {{service.counter}}
Store counter : {{store.counter}}
RxJs data : {{store.data}}
</pre>
</v-app>
</template>
<script lang="ts">
import { MyDataStore } from '#/services/MyDataStore';
import { MyService } from '#/services/MyService';
import Vue from 'vue'
import Component from 'vue-class-component';
#Component
export default class MyForm extends Vue {
public counter = 0;
public store = MyDataStore;
public service = MyService;
clickBouton(){
this.counter++;
MyService.Increment()
MyService.getData();
}
}
</script>
The service
import { of, from, concatMap, delay } from 'rxjs';
import { MyDataStore } from './MyDataStore';
export class MyService {
public static counter = 0
// Update the data store with a new value every 10s
static getData(){
from(["A", "B", "C", "D"]).pipe(concatMap(item => of(item).pipe(delay(10000)))).subscribe((res: any) => {
MyDataStore.data = res;
});
}
static Increment(){
MyDataStore.counter++;
MyService.counter++
}
}
The "DataStore"
export class MyDataStore {
static data: string;
static counter = 0;
}
Any help or tutorial are welcome.
Hey In the end you get a observable. You need to subscribe a value of your component to it and descubscribe it if you destroy your component. If you are using Vue 2 you can use async pipes/filter in order to automate this process.
I found this tutorial:
https://medium.com/#p.woltschkow/a-better-practice-to-implement-http-client-in-vue-with-rxjs-c59f93bfa439

Flutter Mockito verify that callback passed to widget is called

I have a widget that takes a callback which is called when a button is pressed. I am trying to test that the callback is correctly invoked by the button.
I've tried mocking a Function class:
class MockCallback extends Mock implements Function {
call() {}
}
Then passing an instance of the mock class to my widget and simulating a tap:
final mocked = MockCallback();
await tester.pumpWidget(
MyWidget(myCallback: mocked),
);
final clearButtonFinder = find.byType(IconButton);
await tester.tap(clearButtonFinder);
verify(mocked()).called(1);
This results in an error on the verify call saying Used on a non-mockito object. If I put a print statement inside the mocked call, I can see that the tap is indeed calling it.
How can I verify that the callback passed to my widget is getting called once when the button is tapped?
This is how I solved this problem.
class MockCallback {
int _callCounter = 0;
void call() {
_callCounter += 1;
}
bool called(int expected) => _callCounter == expected;
void reset() {
_callCounter = 0;
}
}
No mockito needed.
Probably it is not the best solution - use a stream:
final callbackCalled = BehaviorSubject<void>.seeded(null);
await tester.pumpWidget(
MyWidget(myCallback: () { callbackCalled.add(null); }),
);
//... actions to trigger the callback
await expectLater(callbackCalled, emitsInOrder(<void>[null, null]));
You can use something meaningful instead of 'void' and 'null'.

WebdriverIO function reusability pattern

I am transitioning from Selenium to WebdriverIO and I'm running into some difficulty regarding function reusability. Let me demonstrate with an example:
<nav>
<div><a>Clients</a></div>
<div><a>Accounts</a></div>
<div><a>Packages</a></div>
</nav>
lets say I have a navigation bar with 3 links above. When I land on this page, I want to check if each link exists. My function may look something like this:
class LoginPage extends Page {
get clientsLink() { return $('//a[contains(., "Clients")]'); }
isTabDisplayed() {
if (this.clientsLink.isDisplayed()) {
return true;
} else {
false
}
}
}
this is fine except I would have to write 2 more getters for Accounts and Packages and so my class would look like this:
class LoginPage extends Page {
get clientsLink() { return $('//a[contains(., "Clients")]'); }
get accountsLink() { return $('//a[contains(., "Accounts")]'); }
get packagesLink() { return $('//a[contains(., "Packages")]'); }
isClientTabDisplayed(tab) {
if (this.clientsLink.isDisplayed()) {
return true;
} else {
false
}
}
isAccountsTabDisplayed(tab) {
if (this.accountsLink.isDisplayed()) {
return true;
} else {
false
}
}
isPackagesTabDisplayed(tab) {
if (this.packagesLink.isDisplayed()) {
return true;
} else {
false
}
}
}
at this point, my anxiety kicks in and I start to think of ways I can reuse the isTabDisplayed function where I can pass a string to the getter with my tab name, or something along the lines of that.
Unfortunately, getters do not accept parameters and so far I have not found any resources on google that can help me to solve this issue (most common being Page Object Model which doesn't seem to address this problem)
Is my thought process out of line that I am striving for reusable code in UI testing or am I not googling for correct patterns?
Page Objects in WebdriverIO are just plain ES6 classes. Have a look through the documentation on ES6 classes to understand how you can create functions that you can pass arguments in to.
Now, that being said, what you're doing here isn't necessary. Instead of creating a function which references a getter, why not just reference that getter directly in your test?
const login = new LoginPage();
const isAccountsTabDisplayed = login.accountsLink.isDisplayed();
There's really no reason to create a wrapper function around this.

Is it possible to make a function or class available to all views in Aurelia?

The use case is as follows: We would like to have elements hidden or shown, based on the user's permissions.
The ideal way would be something like this:
<div if.bind="foo != bar && hasPermission('SOME_PERMISSION')"></div>
hasPermission() would in that case be a function that was automatically injected into all viewmodels.
Is that possible? I know we could use base classes for this, but we'd like to avoid that to stay as flexible as possible.
If you're willing to pay the price of a global function (global as in window), import it in your app-bootstrap file, like so:
has-permission.js
export function hasPermission(permission) {
return permission.id in user.permissions; // for example...
}
main.js
import 'has-permission';
export function configure(aurelia) {
// some bootstrapping code...
}
If the service you want to publish globally is a view, you can sidestep exposing it on the window and tell Aurelia's DI to make it available everywhere so you won't have to declare it in every dependent client.
To do so, pass its module ID in the FrameworkConfiguration#globalResources() configuration function:
export function configure(aurelia) {
aurelia.use
.standardConfiguration()
.globalResources('my-kick-ass-view', 'my-awesome-converter');
aurelia.start().then(a => a.setRoot());
}
If you have a service which deals with user permission, it can be injected in all your view-models.
export class UserPermissionService
{
hasPermission(user, permission)
{
return false;
}
}
#inject(UserPermissionService)
export class Users {
userPermissionService;
constructor(userPermissionService) {
this.userPermissionService = userPermissionService;
...
}
hasPermission(user, p)
{
return this.userPermissionService.hasPermission(user, p);
}
}
If you still don't like this, other options are:
a value converter http://aurelia.io/docs.html#/aurelia/binding/1.0.0-beta.1.2.1/doc/article/binding-value-converters
a custom attribute (similar to if it will hide the element)
http://www.foursails.co/blog/custom-attributes-part-1/
depending on what you need, both can use the UserPermissionService singleton from above
Add a .js file in your folder, with export function
ex: utility.js
export function hasPermission(permission) {
return true/false;
};
import the function in view-model
import {hasPermission} from 'utility';
export class MyClass{
constructor(){
this.hasPermission = hasPermission;
}
}
view.html
<div if.bind="foo != bar && hasPermission('SOME_PERMISSION')"></div>

Aurelia DataTables Recompile

I've been exploring Aurelia and so far have loved what I've seen. I've come accross an issue that I'm not really sure how to solve. I used jquery datatables for large results in my current app with angular, using server side fetches. Datatables has a function you can call whenever a new row is added to the table (fnRowCallback - http://legacy.datatables.net/ref#fnRowCallback, or "createdRow" - https://datatables.net/examples/advanced_init/row_callback.html#) - This is really handy as you can recompile the dom after each row (costly I know).
This enables you to reference functions that exist in the current scope (or viewModel) that the datatable exists in. For example:
In my view model:
export class DataTableTest{
test(){
alert('this is a test');
}
}
In the return results from a datatable fetch:
{name:'blah',age:40,actions:"<a click.delegate='test();'>Test</a>"}
For some reason I can't seem to figure out how to recompile an element once it has been added to the dom.
Does anyone have any ideas how you could do this?
UPDATE:
These are the original options I pass to datatables:
var options = {
"fnRowCallback": function (nRow) {
$compile($(nRow).contents())(scope);
}
};
I've tried the following after injecting that compiler service:
"fnRowCallback": function (nRow) {
this.compiler.compile($(nRow).contents()).fragment.innerHTML;
},
But I always get Uncaught TypeError: Cannot read property 'compile' of undefined - I do this in the "attached" function.. If I console.log(this.compiler) outside of these options, it's available. Also, we don't need to return html back to datatables, just run the compile on the contents. Many thanks for all your help!
You can use a compiler service to compile the element:
import {inject, ViewCompiler, ViewResources, Container} from 'aurelia-framework';
/**
* Compiler service
*
* compiles an HTML element with aurelia
*/
#inject(ViewCompiler, ViewResources, Container)
export class Compiler {
viewCompiler: any;
resources: any;
container: any;
constructor(viewCompiler, resources, container) {
this.viewCompiler = viewCompiler;
this.resources = resources;
this.container = container;
}
compile(templateOrFragment, ctx = null, viewSlot = null):any {
if (typeof templateOrFragment === "string") {
var temp = document.createElement('span');
temp.innerHTML = templateOrFragment;
templateOrFragment = temp;
}
var view = this.viewCompiler.compile(templateOrFragment, this.resources).create(this.container, ctx);
return view;
}
}
I use this in Kendo in the cell template callback function (it lets you return a string that will become the cell contents)
function(dataItem) {
var cellctx = { "$item": dataItem, "$parent": ctx };
return this.compiler.compile(templateString, cellctx).fragment.innerHTML;
}
(this happens in Aurelia's bind callback so the ctx is the executionContext)
I just wrap the current data item up in a context and alias it as $item so I can work with it.
Looks something like this:
<kendo-grid>
<kendo-grid-col title="Main Office" field="IsMainOffice">
<kendo-template><img if.bind="$item.IsMainOffice" src="/content/img/accept.png" /></kendo-template>
</kendo-grid-col>
</kendo-grid>