Flutter how to test Either<Failure,List<Object>> - flutter-test

it seems to have the same value with matcher but still can't pass the test probably cuz of the memory address stuff. can anyone let me know how i can test the result when a list is in Either<< Right >>
test('get board list from remote data source', () async {
when(mockBoardRemoteDataSource.getBoards())
.thenAnswer((_) async => tBoardModels);
final result = await repository.getBoards();
verify(mockBoardRemoteDataSource.getBoards());
expect(result, equals(Right(toBoards)));
// Either<Failure, List<BoardInfo>> result;
// (new) Right<dynamic, List<BoardInfo>> Right(List<BoardInfo> _r)
});
//console result
Expected: Right<dynamic, List<BoardInfo>>:<Right([_$_BoardInfo(1, name1, address1), _$_BoardInfo(2, name2, address2)])>
Actual: Right<Failure, List<BoardInfo>>:<Right([_$_BoardInfo(1, name1, address1), _$_BoardInfo(2, name2, address2)])>
package:test_api expect
package:flutter_test/src/widget_tester.dart 455:16 expect
test\features\nurban_honey\data\repositories\board_repository_impl_test.dart 58:9 main.<fn>.<fn>.<fn>
//BoardInfo Implementation
import 'package:equatable/equatable.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'board_info.freezed.dart';
#freezed
class BoardInfo extends Equatable with _$BoardInfo {
BoardInfo._();
factory BoardInfo(int id, String name, String address) = _BoardInfo;
#override
List<Object?> get props => [id, name, address];
}

Thanks to Jay, his answer helps me to made my resolution.
This is how i made the test act:
// Act
var results = (await repository.fetch()).fold(
(failure) => failure,
(response) => response,
);
Then I made a type expectation, matching to the failure type declared on my use case:
In the case of the successful execution
// Assert
expect(results, isA<ResultType>());
In the case of the failure expectation
// Assert
expect(results, isA<FailureType>());
The entire test case looks like the following
test('On successful execution, should returns a SuccessResultType', () async {
// Arrange
repository = MyUseCaseRepository();
// Act
var results = (await repository.fetch()).fold(
(failure) => failure,
(response) => response,
);
// Assert
expect(results, isA<SuccessResultType>());
});
I hope this approach can help anybody!

I've made the test pass by doing this:
result.fold(
(l) => null,
(resultR) => Right(toBoards)
.fold((l) => null, (matcherR) => expect(resultR, matcherR)));
is there better way to do it?

Related

Cypress - extract URL info

I have this URL :
https://www.acme.com/book/passengers?id=h1c7cafc-5457-4564-af9d-2599c6a37dde&hash=7EPbMqFFQu8T5R3AQr1GCw&gtmsearchtype=City+Break
and want to store these values :
id=h1c7cafc-5457-4564-af9d-2599c6a37dde
hash=7EPbMqFFQu8T5R3AQr1GCw
for use in a later test.
How do I extract these values from the URL? I am using Cypress. Thanks.
Please follow the following steps and that's all there is to it.
You can put this snippet into before() hooks of your spec file and you can access them wherever you want.
cy.location().then(fullUrl => {
let pathName = fullUrl.pathname
let arr = pathName.split('?');
let arrayValues = arr[1].split('&');
cy.log(arrayValues[0]);
cy.log(arrayValues[1]);
cy.log(arrayValues[2]);
})
In case anyone needs the correct answer, use the cy.location('search') to extract the search part of the location data.
Then for convenience, convert it to a javascript object with key/value pairs for each item.
Finally, store it in a Cypress alias to use later in the test.
cy.location('search')
.then(search=> {
const searchValues = search.split('?')[1].split('&')
// yields: [
// id=h1c7cafc-5457-4564-af9d-2599c6a37dde,
// hash=7EPbMqFFQu8T5R3AQr1GCw,
// gtmsearchtype=City+Break
// ]
const searchMap = searchValues.reduce((acc,item) => {
const [key,value] = item.split('=')
acc[key] = value.replace('+', ' ')
return acc
}, {})
// yields: {
// id: "h1c7cafc-5457-4564-af9d-2599c6a37dde",
// hash: "7EPbMqFFQu8T5R3AQr1GCw",
// gtmsearchtype: "City Break"
// }
cy.wrap(searchMap).as('searchMap')
})
Using #Srinu Kodi's answer I got it working changing ...then(fullUrl => ... to
...then((fullUrl) => ...

What is the proper way to unit test Service with NestJS/Elastic

Im trying to unit test a Service that uses elastic search. I want to make sure I am using the right techniques.
I am new user to many areas of this problem, so most of my attempts have been from reading other problems similar to this and trying out the ones that make sense in my use case. I believe I am missing a field within the createTestingModule. Also sometimes I see providers: [Service] and others components: [Service].
const module: TestingModule = await Test.createTestingModule({
providers: [PoolJobService],
}).compile()
This is the current error I have:
Nest can't resolve dependencies of the PoolJobService (?).
Please make sure that the argument at index [0]
is available in the _RootTestModule context.
Here is my code:
PoolJobService
import { Injectable } from '#nestjs/common'
import { ElasticSearchService } from '../ElasticSearch/ElasticSearchService'
#Injectable()
export class PoolJobService {
constructor(private readonly esService: ElasticSearchService) {}
async getPoolJobs() {
return this.esService.getElasticSearchData('pool/job')
}
}
PoolJobService.spec.ts
import { Test, TestingModule } from '#nestjs/testing'
import { PoolJobService } from './PoolJobService'
describe('PoolJobService', () => {
let poolJobService: PoolJobService
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [PoolJobService],
}).compile()
poolJobService = module.get<PoolJobService>(PoolJobService)
})
it('should be defined', () => {
expect(poolJobService).toBeDefined()
})
I could also use some insight on this, but haven't been able to properly test this because of the current issue
it('should return all PoolJobs', async () => {
jest
.spyOn(poolJobService, 'getPoolJobs')
.mockImplementation(() => Promise.resolve([]))
expect(await poolJobService.getPoolJobs()).resolves.toEqual([])
})
})
First off, you're correct about using providers. Components is an Angular specific thing that does not exist in Nest. The closest thing we have are controllers.
What you should be doing for a unit test is testing what the return of a single function is without digging deeper into the code base itself. In the example you've provided you would want to mock out your ElasticSearchServices with a jest.mock and assert the return of the PoolJobService method.
Nest provides a very nice way for us to do this with Test.createTestingModule as you've already pointed out. Your solution would look similar to the following:
PoolJobService.spec.ts
import { Test, TestingModule } from '#nestjs/testing'
import { PoolJobService } from './PoolJobService'
import { ElasticSearchService } from '../ElasticSearch/ElasticSearchService'
describe('PoolJobService', () => {
let poolJobService: PoolJobService
let elasticService: ElasticSearchService // this line is optional, but I find it useful when overriding mocking functionality
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
PoolJobService,
{
provide: ElasticSearchService,
useValue: {
getElasticSearchData: jest.fn()
}
}
],
}).compile()
poolJobService = module.get<PoolJobService>(PoolJobService)
elasticService = module.get<ElasticSearchService>(ElasticSearchService)
})
it('should be defined', () => {
expect(poolJobService).toBeDefined()
})
it('should give the expected return', async () => {
elasticService.getElasticSearchData = jest.fn().mockReturnValue({data: 'your object here'})
const poolJobs = await poolJobService.getPoolJobs()
expect(poolJobs).toEqual({data: 'your object here'})
})
You could achieve the same functionality with a jest.spy instead of a mock, but that is up to you on how you want to implement the functionality.
As a basic rule, whatever is in your constructor, you will need to mock it, and as long as you mock it, whatever is in the mocked object's constructor can be ignored. Happy testing!
EDIT 6/27/2019
About why we mock ElasticSearchService: A unit test is designed to test a specific segment of code and not make interactions with code outside of the tested function. In this case, we are testing the function getPoolJobs of the PoolJobService class. This means that we don't really need to go all out and connect to a database or external server as this could make our tests slow/prone to breaking if the server is down/modify data we don't want to modify. Instead, we mock out the external dependencies (ElasticSearchService) to return a value that we can control (in theory this will look very similar to real data, but for the context of this question I made it a string). Then we test that getPoolJobs returns the value that ElasticSearchService's getElasticSearchData function returns, as that is the functionality of this function.
This seems rather trivial in this case and may not seem useful, but when there starts to be business logic after the external call then it becomes clear why we would want to mock. Say that we have some sort of data transformation to make the string uppercase before we return from the getPoolJobs method
export class PoolJobService {
constructor(private readonly elasticSearchService: ElasticSearchService) {}
getPoolJobs(data: any): string {
const returnData = this.elasticSearchService.getElasticSearchData(data);
return returnData.toUpperCase();
}
}
From here in the test we can tell getElasticSearchData what to return and easily assert that getPoolJobs does it's necessary logic (asserting that the string really is upperCased) without worrying about the logic inside getElasticSearchData or about making any network calls. For a function that does nothing but return another functions output, it does feel a little bit like cheating on your tests, but in reality you aren't. You're following the testing patterns used by most others in the community.
When you move on to integration and e2e tests, then you'll want to have your external callouts and make sure that your search query is returning what you expect, but that is outside the scope of unit testing.

What is the correct way to start a MassTransit bus when using the CreateRequestClient method?

I'm using the following code to send a request/response message between two different processes.
This is the process that "sends" the request:
// configure host
var hostUri = new Uri(configuration["RabbitMQ:Host"]);
services.AddSingleton(provider => Bus.Factory.CreateUsingRabbitMq(cfg =>
{
var host = cfg.Host(hostUri, h =>
{
h.Username(configuration["RabbitMQ:Username"]);
h.Password(configuration["RabbitMQ:Password"]);
});
}));
// add request client
services.AddScoped(provider => provider.GetRequiredService<IBus>().CreateRequestClient<QueryUserInRole, QueryUserInRoleResult>(new Uri(hostUri, "focus-authorization"), TimeSpan.FromSeconds(5)));
// add dependencies
services.AddSingleton<IPublishEndpoint>(provider => provider.GetRequiredService<IBusControl>());
services.AddSingleton<ISendEndpointProvider>(provider => provider.GetRequiredService<IBusControl>());
services.AddSingleton<IBus>(provider => provider.GetRequiredService<IBusControl>());
// add the service class so that the runtime can automatically handle the start and stop of our bus
services.AddSingleton<Microsoft.Extensions.Hosting.IHostedService, BusService>();
Here's the implementation of the BusService:
public class BusService : Microsoft.Extensions.Hosting.IHostedService
{
private readonly IBusControl _busControl;
public BusService(IBusControl busControl)
{
_busControl = busControl;
}
public Task StartAsync(CancellationToken cancellationToken)
{
return _busControl.StartAsync(cancellationToken);
}
public Task StopAsync(CancellationToken cancellationToken)
{
return _busControl.StopAsync(cancellationToken);
}
}
The problem is that when the CreateRequestClient code runs, the bus has not started up yet. Thus the response is never returned from the consumer.
If I replace the host configuration with the following code, I get the desired behavior:
var bus = Bus.Factory.CreateUsingRabbitMq(cfg =>
{
var host = cfg.Host(hostUri, h =>
{
h.Username(configuration["RabbitMQ:Username"]);
h.Password(configuration["RabbitMQ:Password"]);
});
});
bus.Start();
services.AddSingleton(bus);
For some reason, the BusService(IHostedService) executes AFTER the AddScoped delegates.
My question is: what is the correct way to start up the bus before using the CreateRequestClient method? Or is the latter approach to starting up the bus sufficient?

Says Jasmine spy is not being called, but I can see that its being called

I can't figure out why Jasmine is claiming that the function I'm spying on isn't being called, especially since it is logging in buildLinksObj when called through and not calling when I remove .and.callThrough() I feel like I've written similar code a bunch of times before without any problem. I'm using Jasmine 2.9
The error message I'm getting is:
1) addToLinks should call buildLinksObj if its given an object with children
it should add the personalized links to PageApp.meta.analytics.links
Expected spy buildLinksObj to have been called.
at UserContext.<anonymous> (http://localhost:9877webpack:///tests/specs/common/FetchPersonalContent.spec.js:854:0 <- tests/app-mcom.js:104553:48)
Here's the except of my code:
FetchPersonalContent.js
const buildLinksObj = (responseObj = {}, targetObj, PageApp) => {
console.log('it logs in buildLinksObj') // This is logging!
}
const addToLinks = (responseArr, personalizedLinks) => {
responseArr.forEach((media) => {
const type = media.type;
const typeObj = media[type];
buildLinksObj(typeObj, personalizedLinks, PageApp);
if (typeObj && typeObj.children) {
console.log('has children!')
console.log('typeObj.children is: ', typeObj.children);
typeObj.children.forEach((child) => {
console.log('has a child')
buildLinksObj(child, personalizedLinks, PageApp);
console.log('buildLinksObj was definitely called. what the heck?')
});
}
});
}
export {buildLinksObj, addToLinks, FetchPersonalContent as default,
};
FetchPersonalContent.spec.js
import * as FetchPersonalContent from '../../../src/FetchPersonalContent'; // my path is definitely correct
describe('it should add the personalized links to PageApp.meta.analytics.links', () => {
it('addToLinks should call buildLinksObj if its given an object with children ', () => {
spyOn(FetchPersonalContent, 'buildLinksObj').and.callThrough();
FetchPersonalContent.addToLinks([{
"personalId": 30718,
"type": "carousel",
"carousel": {}
}], {});
expect(FetchPersonalContent.buildLinksObj).toHaveBeenCalled();
});
});
I'd really appreciate any help!
I have a feeling FetchPersonalContent.buildLinksObj in the spec file is not pointing to the same instance as buildLinksObj in the FetchPersonalContent.js file.
Why is export {FetchPersonalContent as default} required? I am assuming you have shared the complete content of FetchPersonalContent.js in your question.
Possible solutions:
You can try removing FetchPersonalContent from the export statement.
Or
Instead of
export {buildLinksObj, addToLinks, FetchPersonalContent as default,
};
You can directly export the constants in FetchPersonalContent.js file.

Using side effects in Akka Streams to implement commands received from a websocket

I want to be able to click a button on a website, have it represent a command, issue that command to my program via a websocket, have my program process that command (which will produce a side effect), and then return the results of that command to the website to be rendered.
The websocket would be responsible for updating state changes applied by different actors that are within the users view.
Example: Changing AI instructions via the website. This modifies some values, which would get reported back to the website. Other users might change other AI instructions, or the AI would react to current conditions changing position, requiring the client to update the screen.
I was thinking I could have an actor responsible for updating the client with changed information, and just have the receiving stream update the state with the changes?
Is this the right library to use? Is there a better method to achieve what I want?
You can use akka-streams and akka-http for this just fine. An example when using an actor as a handler:
package test
import akka.actor.{Actor, ActorRef, ActorSystem, Props, Stash, Status}
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.ws.{Message, TextMessage}
import akka.http.scaladsl.server.Directives._
import akka.stream.scaladsl.{Flow, Sink, Source, SourceQueueWithComplete}
import akka.stream.{ActorMaterializer, OverflowStrategy, QueueOfferResult}
import akka.pattern.pipe
import scala.concurrent.{ExecutionContext, Future}
import scala.io.StdIn
object Test extends App {
implicit val actorSystem = ActorSystem()
implicit val materializer = ActorMaterializer()
implicit def executionContext: ExecutionContext = actorSystem.dispatcher
val routes =
path("talk") {
get {
val handler = actorSystem.actorOf(Props[Handler])
val flow = Flow.fromSinkAndSource(
Flow[Message]
.filter(_.isText)
.mapAsync(4) {
case TextMessage.Strict(text) => Future.successful(text)
case TextMessage.Streamed(textStream) => textStream.runReduce(_ + _)
}
.to(Sink.actorRefWithAck[String](handler, Handler.Started, Handler.Ack, Handler.Completed)),
Source.queue[String](16, OverflowStrategy.backpressure)
.map(TextMessage.Strict)
.mapMaterializedValue { queue =>
handler ! Handler.OutputQueue(queue)
queue
}
)
handleWebSocketMessages(flow)
}
}
val bindingFuture = Http().bindAndHandle(routes, "localhost", 8080)
println("Started the server, press enter to shutdown")
StdIn.readLine()
bindingFuture
.flatMap(_.unbind())
.onComplete(_ => actorSystem.terminate())
}
object Handler {
case object Started
case object Completed
case object Ack
case class OutputQueue(queue: SourceQueueWithComplete[String])
}
class Handler extends Actor with Stash {
import context.dispatcher
override def receive: Receive = initialReceive
def initialReceive: Receive = {
case Handler.Started =>
println("Client has connected, waiting for queue")
context.become(waitQueue)
sender() ! Handler.Ack
case Handler.OutputQueue(queue) =>
println("Queue received, waiting for client")
context.become(waitClient(queue))
}
def waitQueue: Receive = {
case Handler.OutputQueue(queue) =>
println("Queue received, starting")
context.become(running(queue))
unstashAll()
case _ =>
stash()
}
def waitClient(queue: SourceQueueWithComplete[String]): Receive = {
case Handler.Started =>
println("Client has connected, starting")
context.become(running(queue))
sender() ! Handler.Ack
unstashAll()
case _ =>
stash()
}
case class ResultWithSender(originalSender: ActorRef, result: QueueOfferResult)
def running(queue: SourceQueueWithComplete[String]): Receive = {
case s: String =>
// do whatever you want here with the received message
println(s"Received text: $s")
val originalSender = sender()
queue
.offer("some response to the client")
.map(ResultWithSender(originalSender, _))
.pipeTo(self)
case ResultWithSender(originalSender, result) =>
result match {
case QueueOfferResult.Enqueued => // okay
originalSender ! Handler.Ack
case QueueOfferResult.Dropped => // due to the OverflowStrategy.backpressure this should not happen
println("Could not send the response to the client")
originalSender ! Handler.Ack
case QueueOfferResult.Failure(e) =>
println(s"Could not send the response to the client: $e")
context.stop(self)
case QueueOfferResult.QueueClosed =>
println("Outgoing connection to the client has closed")
context.stop(self)
}
case Handler.Completed =>
println("Client has disconnected")
queue.complete()
context.stop(self)
case Status.Failure(e) =>
println(s"Client connection has failed: $e")
e.printStackTrace()
queue.fail(new RuntimeException("Upstream has failed", e))
context.stop(self)
}
}
There are lots of places here which could be tweaked, but the basic idea remains the same. Alternatively, you could implement the Flow[Message, Message, _] required by the handleWebSocketMessages() method by using GraphStage. Everything used above is also described in detail in akka-streams documentation.

Resources