How to override the response in Jasmine Spyon - karma-jasmine

I have an mockservice and i need to override the mock service response in particular test cases, but it is taking an value from the mock service instead of new response in spyon.
here i have a mock service and return some value.
export class MockService {
getProducts() {
const data = [{ 'productI': 1, 'productName': 'Phone', 'price': 19.96 },
{ 'productID': 3, 'productName': 'Phones', 'price': 19.96 },
{
'productID': 2, 'productName': 'Laptop', 'price': 2000.96
}];
return Observable.of(data);
}
}
In spec one of the test case i have getting the above response and test case success.
it('call subscribe get Products and get into success', () => {
spyOn(mockService, 'getProduct').and.returnValue(
observable.of();
)
});
component.ngOnInit();
In another test cases i need to test fail scenario.
it("Test 409 failure in service call',()=>{
spyOn(mockService, 'getProduct').and.returnValue(
throwError({status:409})
});
component.ngOnInit();
});
In this case , getting a value from predefined mock respone.Why it is not get into error after provide throwError in spyOn

Related

How to use a part of intercepted endpoint as a variable in my stub with Cypress

I am testing a frontend and I want to make my test more efficient
I have the following custom command:
cy.intercept('**/api/classification/dd86ac0a-ca23-413b-986c-535b6aad659c/items/**',
{ fixture: 'ItemsInEditor.json' }).as('ItemsInEditorStub')
This works correctly and is intercepts 25 times :). But the Id in the stub file has to be the same as in the requested Endpoint. Otherwise the frontEnd wilt not process it.
At this point I do not want to make 25 stubfiles in the fixture map.
In the printscreen you can see the different calls I need to intercept. The last ID I would like to save as variable and use it in the stub file
The Stub is like this:
{
"item": {
"version": 3,
"title": "Cars",
"rows": [],
"id": "dynamicIdBasedOnEndPoint" <- *Can we make it dynamic based on the ID in the endpoint*
},
"itemState": "Submitted"
}
UPDATE:
What I have for now is just the basic I guess:
cy.intercept('**/api/classification/*/items/**', {
body:
{
item: {
version: 3,
title: 'Cars',
rows: [],
id: '55eb5a28-24d8-4705-b465-8e1454f73ac8' //Still need this value to be dynamic and always the same as the intercepted '**'(wildcard)
},
itemState: "Submitted"
}
})
.as('ItemsInEditorStub')
cy.fixture('ItemsInEditor.json').then(ModFixture => {
cy.intercept('GET', '**/api/classification/**/items/id/**', (req) => {
const id = req.url.split('/').pop(); // last part of url path
ModFixture.item.id = id; // add the id dynamically
req.reply(ModFixture); // send altered fixture
})
}).as('ItemsInEditorStub')
Thanks to #Fody
You can make a dynamic fixture using javascript.
Ref Providing a stub response with req.reply()
cy.fixture('ItemsInEditor.json').then(fixture => {
cy.intercept('**/api/classification/dd86ac0a-ca23-413b-986c-535b6aad659c/items/**',
(req) => {
const id = req.url.split('/').pop(); // last part of url path
fixture.item.id = id; // add the id dynamically
req.reply(fixture); // send altered fixture
}
).as('ItemsInEditorStub')
})

Freeze redirect in cypress

I would like to test a GA4 product click event. For this I write the required data in the data layer and I want to see if the correct data is in the data layer. However, when I click on the product in Cypress, the redirect is faster than the test can read the data layer. Is there any way I can pause or freeze the redirect?
Here the expectet data in the Datalayer:
select_item: {
event: 'select_item',
ecommerce: {
item_name: 'Artiklename',
item_id: '000000',
price: 1.19,
currency: 'EUR',
item_brand: 'Brand',
item_category: 'category',
item_category2: 'category2',
item_category3: 'category3',
item_category4: 'category4',
index: 1,
quantity: 1,
item_list_name: "List Name"
},
},
Here the actual Test:
context('Google Analytics 4: should track select_item event', function () {
it('should track select item on search page', function () {
cy.getTrackingData('expressShippingArticle', 'select_item').then(
(expectedSelectItemEvent) => {
// act
cy.visitWithBasicAuth(
routes.category.resultList(
'000/SomeArticle'
)
)
//assert
cy.getSpecificEventFromDataLayer('select_item').then(
(event) => {
cy.wrap(event).should('not.exist')
}
)
// act
cy.get(selectors.resultList.productInResultList)
.first()
.click()
cy.getSpecificEventFromDataLayer('select_item').then(
(actualSelectItemEvent) => {
cy.wrap(actualSelectItemEvent, { timeout: 0 }).should(
spok(expectedSelectItemEvent)
)
}
)
}
)
})
})
Not sure if this works with GA4, but if you want to delay a network request/response add an intercept with delay option
cy.intercept(redirect-url, (req) => {
req.reply(res => {
res.setDelay(2000)
})
})
// act
cy.get(selectors.resultList.productInResultList).first().click()
...

Ember JS testing - Factory guy

I am using ember 2.18 and ember-data-factory-guy 3.3.0.
I want to test an action inside a component. In the action, I am using makeList in order to create and return a list of models. In my ember app, I pass the store to the component and I am doing a query when I a call the action.
Here is my Factory:
import FactoryGuy from 'ember-data-factory-guy';
FactoryGuy.define('contact', {
sequences: {
first_name: (num) => `FirstName${num}`,
last_name: (num) => `LastName${num}`,
email: (num) => `contact${num}#example.com`,
phone: (num) => `01234567${num}`,
linkedin: (num) => `samplelinkedinurl${num}`,
},
default: {
first_name: FactoryGuy.generate('first_name'),
last_name: FactoryGuy.generate('last_name'),
email: FactoryGuy.generate('email'),
phone: FactoryGuy.generate('phone'),
linkedin: FactoryGuy.generate('linkedin'),
position: 'CEO',
client_office: FactoryGuy.belongsTo('office')
},
traits: {
withClient: {
client: FactoryGuy.belongsTo('client')
},
withOffice: {
client_office: FactoryGuy.belongsTo('office')
}
}
});
Additionaly, my action is the followin:
_this.store.query('contact', {term: searchTerm}).then(function(contacts) { ... })
I have create a TestStore class in order to test actions like these. It is a minimal replication of the querying methods of ember data store. The query method looks like that:
query(modelName, attributes, trait=null) {
console.log('ATTRIBUTES PASSED TO TEST STORE QUERY: ', attributes)
// make a new record of selected model with factory guy
let _this = this,
records = Ember.isEmpty(trait) ? makeList(modelName, 4) : makeList(modelName, 4, trait);
// Push it to test-store
if (!this.models[modelName]) {
this.models[modelName] = Ember.A([]);
}
records.forEach(function(record) {
_this.models[modelName].pushObject(record); })
// Create promise to return
let recordPromise = new Ember.RSVP.Promise((resolve) => {
resolve(records);
});
return DS.PromiseArray.create({promise: recordPromise});
}
In rendering tests it is working just fine. If I am to run the action manually (e.g. like in unit tests ), I get the following error:
FactoryGuy does not have the application's
manualSetup is not working as well, as the store service is stuck in the "willDestroy()" of the store and _pushedInternalModels is null so no Models can be pushed to the store.
Any ideas/suggestions on that?

How to "Actually" Test an Angular 2 Service

I am new to testing calls to an API. I have this unit test code in Angular 2:
beforeEach(inject([JobListService, MockBackend],
(testedService: JobListService, mockBackend: MockBackend) => {
service = testedService;
backend = mockBackend;
backend.connections.subscribe((c) => {
c.mockRespond(new Response(
new ResponseOptions({body: JSON.stringify(JOBLISTMOCK)})
));
});
}));
describe('getAll', () => {
it('should return jobs', () => {
service.getAll(1, 10, '0').subscribe(response => {
console.log(response.data.length);
expect(response.data.data.length).toBeGreaterThan(0);
});
});
it('should return jobs based on company ID', () => {
service.getAll(1, 10, '26').subscribe(response => {
console.log(response.data.data.length);
expect(response.data.data.length).toEqual(1);
});
});
});
it has the url structure:
http://example.com/api/jobs/1/10/26
where first and second segment is pagination and the 3rd segment is a company ID.
I am testing this service function:
getAll(page: number, pageSize: number, company: string): Observable<any> {
if (company !== 'null') {
return this.http.get(`${this.conf.apiUrl}/jobs/companies/get/${page}/${pageSize}/${company}`)
.map((response: Response) => response.json());
} else {
return this.http.get(`${this.conf.apiUrl}/jobs/companies/get/${page}/${pageSize}/0`)
.map((response: Response) => response.json());
}
}
I have this mock response:
{
'id': 13,
'title': 'Sample Title',
'valid_from': '2016-01-01',
'valid_to': '2016-02-01',
'field_id': '1',
'image': '',
'description': null,
'user_id': 0,
'company_id': 26,
'created_at': '2017-01-23 14:37:01',
'updated_at': '2017-01-23 14:37:01',
'fields': {
'field_id': 1,
'name': 'Respiratory Therapy Technician'
}
},
{
'id': 15,
'title': 'Sample Title',
'valid_from': '2016-01-01',
'valid_to': '2016-02-01',
'field_id': '1',
'image': 'asd',
'description': 'This is my sample des',
'user_id': 0,
'company_id': 0,
'created_at': '2017-01-23 14:37:27',
'updated_at': '2017-01-23 14:37:27',
'fields': {
'field_id': 1,
'name': 'Respiratory Therapy Technician'
}
}
}
the 2nd one fails, obviously, because my mock response is set to companies that have 0 and 26 as IDs.
I get that I am mocking a response via a mockbackend but what I want is to test the function such that getAll() returns only the jobs with company_id 26. But my mock response is static. Is there anyway that I can make a "dynamic mock backend" that will work with what I want to test?

How can I use Ember Data's FixtureAdapter with real API content

I want to populate my Ember Data fixtures with real content taken from an API data dump instead of the standard fixtures. I don't want to use the API directly.
I want to do this so I can imitate a local instance of the API data.
How can I streamline this and also how might I configure the adapter to allow this?
Consider this default FIXTURE:
App.Comment = DS.Model.extend({
article: DS.belongsTo('article'),
author: DS.belongsTo('user'),
dateCreated: DS.attr('date', {readOnly: true}),
dateModified: DS.attr('date', {readOnly: true}),
description: DS.attr('string')
});
App.Comment.FIXTURES = [{
id: 1,
temp: 1,
author: 1,
dateCreated: 'Mon Jul 28 2014 12:00:00 GMT+1000 (EST)',
dateModified: null,
description: 'lorem ipsum'
}];
Consider this API response:
{"comments": [
{
"articleID": 1,
"description": "I am a comment",
"authorID": 1,
"dateCreated": "2014-09-04T02:39:00",
"createdBy": "Elise Chant",
"dateModified": "2014-09-04T02:39:00",
"id": 1
},
{
"articleID": 1,
"description": "I am another comment",
"authorID": 1,
"dateCreated": "2014-09-04T02:48:00",
"createdBy": "Elise Chant",
"dateModified": "2014-09-04T02:48:00",
"id": 2
}
]}
Get your backend to provide a data dump method from the API with the resources, such as:
http://myapi/dump
The method shall return a zipped folder of files representing the site's resources, such as Comment.js, User.js, Article.js.
Each of these files should return the JSON resource wrapped by DS.Model.FIXTURES array, such as
App.Comment.FIXTURES =
[
{
"articleID": 1,
"userID": 1,
"description": "I am a comment.",
"category": 0,
"authorID": 1,
"dateCreated": "2014-09-04T02:39:00",
"id": 1
},
// ...
];
Remember to make sure that each .js file is an included script tag in html and appears after its corresponding model. Check this is available in the Browser's Developer Console.
Finally, In order to correctly connect asynchronous relationships such as articleID and authorID, property names need to be normalised like that would be if you were using normal fixture data. So configure the adapter to strip 'ID' from the end of any belongsTo relationships by parsing the FIXTURES payload:
if (App.ENV === 'DEV') {
App.ApplicationSerializer = DS.JSONSerializer.extend({
// access to the payload
extractArray: function(store, type, payload) {
var self = this;
return payload.map(function(item) {
// normalise incoming data
return self.normalize(type, item);
});
},
normalize: function(type, hash) {
if (!hash) { return hash; }
var normalizedHash = {},
normalizedProp;
for (var prop in hash) {
if (!!prop.match(/ID$/)) {
// belongs to / has Many attribute
// remove 'ID' from the end of the property name
normalizedProp = prop.substr(0, prop.length-2);
} else { // regular attribute
normalizedProp = prop;
}
normalizedHash[normalizedProp] = hash[prop];
}
this.normalizeId(normalizedHash);
this.normalizeUsingDeclaredMapping(type, normalizedHash);
this.applyTransforms(type, normalizedHash);
return normalizedHash;
}
});
App.ApplicationAdapter = DS.FixtureAdapter.extend({
simulateRemoteResponse: true,
latency: 1000,
// This "unsets" serializer so that the store will lookup the proper serializer
// #see https://github.com/emberjs/data/issues/1333
serializer: function() {
return;
}.property()
});
} else {
DS.CustomRESTSerializer = DS.RESTSerializer.extend({
keyForRelationship: function(key, kind) {
if (kind === 'belongsTo') {
return key + 'ID';
} else {
return key;
}
}
});
App.ApplicationAdapter = DS.RESTAdapter.extend({
host: App.HOST,
namespace: App.NAMESPACE,
ajax: function(url, method, hash) {
hash = hash || {}; // hash may be undefined
hash.crossDomain = true;
hash.xhrFields = {withCredentials: true};
return this._super(url, method, hash);
},
defaultSerializer: 'DS/customREST'
});
}