NGRX jest-marbles Testing Effect Involving forkJoin Operator - unit-testing

Unit Testing an Effect that Incorporates a forkJoin Operator
I have an Angular 15 project using NGRX. I'm writing unit tests against my store and associated modules.
My effect basically works like a polling service and calls a service inside a forkJoin operator. The code is below.
getGroupFlow$ = createEffect(() =>
this.actions$.pipe(
ofType(StatusPollingActions.pollFlow),
tap(() => this.continuePolling = true),
withLatestFrom(of(environment.statusPollingInterval)),
switchMap(([action, pollingInterval]) =>
timer(0, pollingInterval).pipe(
takeWhile(() => this.continuePolling, true),
switchMap(() =>
forkJoin([
this.nifiService.getProcessGroupFlow(this.inputGroupId),
this.nifiService.getProcessGroupFlow(this.processingGroupId),
this.nifiService.getProcessGroupFlow(this.outputGroupId),
this.nifiService.getConnectionsForGroup(this.mainCanvasId),
]).pipe(
map(([incoming, processing, outgoing, groupConnections]) =>
StatusPollingActions.pollFlowSuccess({
incomingGroupFlow: incoming,
processingGroupFlow: processing,
outputGroupFlow: outgoing,
groupConnections: groupConnections,
})
),
catchError((error) =>
of(StatusPollingActions.pollFlowFailure({ error }))
)
)
)
)
)
)
);
Of note... the variables referenced in the effect are defined below:
continuePolling: boolean variable scoped to the class
statusPollingInterval: number indicating how frequently to poll (passed in from environment)
I'm a bit new to writing tests against NGRX and I'm using jest and jest-marbles for my test cases.
I need help building out the test case to model the expected flow and output.
Any help would be greatly appreciated!

Related

InvalidArgumentException: Unknown formatter while writing unit tests

I am writing phpUnit tests for our application, So for this I wrote a model factory, after that when I try to run the unit test then I am getting an error like " InvalidArgumentException: Unknown formatter 'publicId' ". I have declared table's all column names in my Model factory. Is it required to mention all columns in the factory?
ModelFactory.php
$factory->define(App\Campaign::class, function (Faker\Generator $faker) {
return [
'public_id' => $faker->publicId,
'client_id' => $faker->clientID,
'name' => $faker->name,
'criteria_age' => $faker->criteriaAge,
'criteria_state' => $faker->criteriaState,
'criteria_postcode' => $faker->criteriaPostcode,
'dncr_required' => $faker->dncrRequired,
'criteria_state' => $faker->criteriaState,
'active' => $faker->active,
'method' => $faker->method,
'server_parameters' => $faker->serverParameters,
'parameter_mapping' => $faker->parameterMapping,
];
});
\tests\Unit\Campaign\CampaignTest.php
namespace Tests\Unit\Campaign;
use App\Campaign;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class CampaignTest extends TestCase
{
use DatabaseTransactions;
public function testCampaignCreation()
{
factory(\App\Campaign::class)->create(['name' => 'tinku']);
$this->seeInDatabase('campaigns', ['name' => 'tinku']);
}
}
after running "phpunit tests/Unit/Campaign/CampaignTest.php" I got this error "InvalidArgumentException: Unknown formatter 'publicId'". I am new to Laravel I know there is a procedure to create factories but I couldn't figure out. Hope someone helps. Thanks.
The formatter is from Faker not Laravel and you can only use Faker formatters Faker ships with.
The error message just tells you that there is no such formatter named publicId. For a list of all Faker formatters please see: https://github.com/fzaninotto/Faker#formatters
If you compare that list with the formatters you've used in your example it becomes more and more obvious that you confused the formatters with some database properties, most likely a translation failure from an existing example? But I think you will know better and this hopefully gives you the information you need to continue setting up your test-case.

How to test RxJs4 streams containing promise chains

I'm having difficulty grasping how to swap out a promise chain from my Rx stream so I can test it.
The snippet below is from the documentation of RxJs createResolvedPromise and has been enhanced with a chained .then(()=>..) to better simulate my code. When running this example the .then() is not applied to the results emitted.
var scheduler = new Rx.TestScheduler();
// Create resolved promise
var xs = scheduler.createResolvedPromise(201, 'bar')
.then(val => 'foo:'+val);
// Note we'll start at 200 for subscribe, hence missing the 150 mark
var res = scheduler.startScheduler(
// fromPromise needs scheduler explicitly, see https://github.com/Reactive-Extensions/RxJS/issues/976
() => Rx.Observable.fromPromise(xs, scheduler)
);
// expected: value to be foo:bar but got bar
console.log(res.messages.map(msg => `msg:#${msg.time} val:${msg.value}`));
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.1.0/rx.all.js"></script>
It seems that the .then() is ignored when using the TestScheduler (although createResolvedPromise returns a Mock promise with implementation of .then to also return a MockPromise...).
The example above is heavily simplified, The real code would be something along:
const myStream = Rx.Observable.interval(100)
.flatMap(() => doPromiseOne().then(res => doPromiseTwo(res)))
.subscribe(console.log);
So what i am trying to attain in my test is that i can resolve promiseOne (using createResolvedPromise?) and let it flow through doPromiseTwo so i can observe the results.

cakephp 2.6 controller test case throwing MissingActionException on duplicate testAction()-call

I hope anyone can help me out with my testing environment.
my setup
I am implementing unit tests based on phpunit 3.7.22 with the cake release 2.6.9. Running on ubuntu 12.04 LTS with PHP 5.4.43-1 and postgresql 9.1.
I immplemented controller tests mocking cakes Auth Component to have a user in the session, since my tests depent on that. My controllers return json results, since its an API for a JS-based frontend. I call my controller methods using the testAction() call of a generated controller.
<?php
App::uses('RequesttypesController', 'Svc.Controller');
class RequesttypesWithResultControllerTest extends ControllerTestCase
{
public $fixtures = array(
'app.requesttype',
'app.user',
'app.privilege',
'app.groupsprivilege',
'app.groupsuser',
'app.groupscompany',
'app.company',
);
/**
* Mock the requesttype object so that it can return results depending on the desired outcome
*
* #see CakeTestCase::setUp()
*/
public function setUp()
{
parent::setUp();
$this->controller = $this->generate('Svc.Requesttypes', array(
'models' => array(
'Requesttype'
),
'components' => array(
'Auth' => array(
'user'
),
'Session',
'RequestHandler'
)
));
$this->controller->Auth->staticExpects($this->any())
->method('user')
->will($this->returnValue(array(
'id' => 123,
'username' => 'myTestUser',
'company' => 'myTestCompany',
'usertype_id' => '456',
))
);
$authResult = $this->controller->Auth->user();
}
public function tearDown()
{
parent::tearDown();
unset($this->controller);
}
/**
* A logged in user produces a number of requesttypes
*/
public function testLoggedInUser()
{
$result = $this->testAction('/svc/requesttypes/getMyRequesttypes', array('return' => 'vars'));
$this->assertNotEmpty($this->vars, 'Did not receive webservice response');
$this->assertTrue(isset($this->vars['data']['code']), 'Received invalid webservice response');
$this->assertEqual($this->vars['data']['code'], SvcAppController::RESPONSE_CODE_SUCCESS);
}
}
?>
This test passes without errors. Now I want to test my controller-action with different setups, for example users with a different usertype, from a different company, and so on. If I now create a second test-method in my RequesttypesWithResultControllerTest-class, calling the same testAction-url, i get a MissingActionException saying:
"Action RequesttypesController::() could not be found."
It seems that the testAction calls an empty controller-action, even if the action-url is passed as a parameter. I tried reinitializing the controller by nulling it and calling $this->generate() again, but this does not help either.
Of course I can help myself out by creating an own test-controller for every test ending up in a bunch of duplicate test-code, but this somehow seems not right to me.
Am I misusing the test-environment or how can this exception be explained? Any ideas?
Thanks in advance for sharing my headache!
After some further code debugging we finally found the error. We accidently changed the require statement of the last line of the /Config/routes.php file to a require_once because of some "Class already defined Exceptions" thrown in the test-environment.
Wrong routes.php:
require_once CAKE . 'Config' . DS . 'routes.php';
For the application itself that made no difference, since the routes are only needed to be initialized once per request. But in a test-environment, the routes are reinitialized several times, which was not possible anymore with the require_once include.
This is how the line is supposed to look like, which it does by default:
Correct routes.php:
require CAKE . 'Config' . DS . 'routes.php';

Unit testing a directive that defines a controller in AngularJS

I'm trying to test a directive using Karma and Jasmine that does a couple of things. First being that it uses a templateUrl and second that it defines a controller. This may not be the correct terminology, but it creates a controller in its declaration. The Angular application is set up so that each unit is contained within its own module. For example, all directives are included within module app.directive, all controllers are contained within app.controller, and all services are contained within app.service etc.
To complicate things further, the controller being defined within this directive has a single dependency and it contains a function that makes an $http request to set a value on the $scope. I know that I can mock this dependency using $httpBackend mock to simulate the $http call and return the proper object to the call of this function. I've done this numerous times on the other unit tests that I've created, and have a pretty good grasp on this concept.
The code below is written in CoffeeScript.
Here is my directive:
angular.module('app.directive')
.directive 'exampleDirective', [() ->
restrict: 'A'
templateUrl: 'partials/view.html'
scope: true
controller: ['$scope', 'Service', ($scope, Service) ->
$scope.model = {}
$scope.model.value_one = 1
# Call the dependency
Service.getValue()
.success (data) ->
$scope.model.value_two = data
.error ->
$scope.model.value_two = 0
]
]
Here is the dependency service:
angular.module("app.service")
.factory 'Service', ['$http', ($http) ->
getValue: () ->
options.method = "GET"
options.url = "example/fetch"
$http _.defaults(options)
Here is the view:
<div>
{{model.value_one}} {{model.value_two}}
</div>
I've simplified this quite a bit, as my goal is only to understand how to wire this up, I can take it from there. The reason I'm structuring it this way is because I did not initially create this. I'm working on writing tests for an existing project and I don't have the ability to configure it any other way. I've made an attempt to write the test, but cannot get it to do what i want.
I want to test to see if the values are being bound to the view, and if possible to also test to see if the controller is creating the values properly.
Here is what I've got:
'use strict'
describe "the exampleDirective Directive", ->
beforeEach module("app.directive")
beforeEach module("app/partials/view.html")
ServiceMock = {
getValue : () ->
options.method = "GET"
options.url = "example/fetch"
$http _.defaults(options)
}
#use the mock instead of the service
beforeEach module ($provide) ->
$provide.value "Service", ServiceMock
return
$httpBackend = null
scope = null
elem = null
beforeEach inject ($compile, $rootScope, $injector) ->
# get httpBackend object
$httpBackend = $injector.get("$httpBackend")
$httpBackend.whenGET("example/fetch").respond(200, "it works")
#set up the scope
scope = $rootScope
#create and compile directive
elem = angular.element('<example-directive></example-directive>')
$compile(elem)(scope)
scope.$digest()
I don't know how close I am, or if this is even correct. I want to be able to assert that the values are bound to the view correctly. I've used Vojtajina's example to set up html2js in my karma.js file to allow me to grab the views. I've done a lot of research to find the answer, but I need some help. Hopefully a programmer wiser than I can point me in the right direction. Thank you.
Create the element in karma, then use the .controller() function with the name of your directive to grab the controller. For your example, replace the last couple of lines with these:
elem = angular.element('<div example-directive></div>');
$compile(elem)($rootScope);
var controller = elem.controller('exampleDirective');
Note, that given how you defined your directive, it should be by attribute, and not as an element. I'm also not 100% sure, but I don't think you need the scope.$digest; usually I just put anything that needs to be applied into a scope.$apply(function() {}) block.

How to develop input object with TDD / BDD?

I have a method called ProcessPayment() that I'm developing via BDD and mspec. I need help with a new challenge. My user story says:
Given a payment processing context,
When payment is processed with valid payment information,
Then it should return a successful gateway response code.
To set up the context, I am stubbing my gateway service using Moq.
_mockGatewayService = Mock<IGatewayService>();
_mockGatewayService.Setup(x => x.Process(Moq.It.IsAny<PaymentInfo>()).Returns(100);
Here's the spec:
public class when_payment_is_processed_with_valid_information {
static WebService _webService;
static int _responseCode;
static Mock<IGatewayService> _mockGatewayService;
static PaymentProcessingRequest _paymentProcessingRequest;
Establish a_payment_processing_context = () => {
_mockGatewayService = Mock<IGatewayService>();
_mockGatewayService
.Setup(x => x.Process(Moq.It.IsAny<PaymentInfo>())
.Returns(100);
_webService = new WebService(_mockGatewayService.Object);
_paymentProcessingRequest = new PaymentProcessingRequest();
};
Because payment_is_processed_with_valid_payment_information = () =>
_responseCode = _webService.ProcessPayment(_paymentProcessingRequest);
It should_return_a_successful_gateway_response_code = () =>
_responseCode.ShouldEqual(100);
It should_hit_the_gateway_to_process_the_payment = () =>
_mockGatewayService.Verify(x => x.Process(Moq.It.IsAny<PaymentInfo>());
}
The method should take a `PaymentProcessingRequest' object (not domain obj), map that obj to a domain obj, and pass the domain obj to the stubbed method on the gateway service. The response from the gateway service is what gets returned by the method. However, because of the way I am stubbing my gateway service method, it doesn't care what gets passed in to it. As a result, it seems I have no way to test whether or not the method maps the request object to the domain object properly.
When can I do here and still adhere to BDD?
To check that the object sent to your IGatewayService is correct, you can use a callback to set a reference to the domain object. You can then write your assertions on properties of that object.
Example:
_mockGatewayService
.Setup(x => x.Process(Moq.It.IsAny<PaymentInfo>())
.Callback<PaymentInfo>(paymentInfo => _paymentInfo = paymentInfo);
So from what I understand,
You want to test the mapping logic in the WebService.ProcessPayment method ; there is a mapping of an input parameter A to an object B, which is used as an input to a GateWayService collaborator.
It should_hit_the_gateway_to_process_the_payment = () =>
_mockGatewayService.Verify(
x => x.Process( Moq.It.Is<PaymentInfo>( info => CheckPaymentInfo(info) ));
Use the Moq It.Is constraint which takes in a Predicate (a test for the argument to satisfy). Implement CheckPaymentInfo to assert against the expected PaymentInfo.
e.g. to check if Add is Passed an even number as an argument,
mock.Setup(foo => foo.Add(It.Is<int>(i => i % 2 == 0))).Returns(true);