Related
I am trying to write a simple test for my vue component. Since the vue component makes an async call on mount and updates the vuex store, dispatch is called during mount, which breaks my existing unit tests. Any idea how to overcome this? Since I am mocking table data, I don't need the mounted() function to be called when running the tests.
MyTable.spec.js
const wrapper = shallowMount(MyTable, {
propsData: {
tableData: [
{
"product_id":10826345236,
"name":"T-Shirt"
}
],
columns: ['product_id', 'name'],
headings: ['Product ID', 'Name'],
actionType: 'loadProducts'
}
});
...
MyTable.vue
...
data() {
return {
options: {
...
}
};
},
methods: {
getHeadings() {
let headings = {};
this.columns.map((key, i) => headings[key] = this.headings[i]);
return headings;
},
setColumnClasses() {
let classes = {};
this.columns.map((key) => classes[key] = key);
return classes;
},
loadRecords(actionType) {
this.$store.dispatch(actionType);
}
},
props: {
tableData: {
type: Array,
required: true
},
columns: {
type: Array,
required: true
},
actionType: {
type: String,
required: true
},
headings: {
type: Array,
required: true
},
...
},
mounted() {
this.loadRecords(this.actionType);
}
You are getting this error message because Vue (when mounted) is expecting that the this.$store is defined, and while it might be within your application, you are not importing it, nor are you mocking it.
Here is your test function code you provided:
const wrapper = shallowMount(MyTable, {
propsData: {
tableData: [
{
"product_id":10826345236,
"name":"T-Shirt"
}
],
columns: ['product_id', 'name'],
headings: ['Product ID', 'Name'],
actionType: 'loadProducts'
}
});
Here is what you need to add:
import store from '../path/to/store.js';
import { createLocalVue, shallowMount } from '#vue/test-utils';
// You will want to create a local Vue instance for testing purposes: https://vue-test-utils.vuejs.org/api/#createlocalvue
const localVue = createLocalVue();
// This tells the local Vue instance to use Vuex for the store mechanism.
localVue.use(Vuex);
const wrapper = shallowMount(MyTable, {
localVue, // Bind the local Vue instance when we shallow-mount the component.
store, // Bind the store so all of the methods are available when invoked.
propsData: {
tableData: [
{
"product_id":10826345236,
"name":"T-Shirt"
}
],
columns: ['product_id', 'name'],
headings: ['Product ID', 'Name'],
actionType: 'loadProducts'
}
});
Subscriptions with Nexus are undocumented but I searched Github and tried every example in the book. It's just not working for me.
I have cloned Prisma2 GraphQL boilerplate project & my files are as follows:
prisma/schema.prisma
datasource db {
provider = "sqlite"
url = "file:dev.db"
default = true
}
generator photon {
provider = "photonjs"
}
generator nexus_prisma {
provider = "nexus-prisma"
}
model Pokemon {
id String #default(cuid()) #id #unique
number Int #unique
name String
attacks PokemonAttack?
}
model PokemonAttack {
id Int #id
special Attack[]
}
model Attack {
id Int #id
name String
damage String
}
src/index.js
const { GraphQLServer } = require('graphql-yoga')
const { join } = require('path')
const { makeSchema, objectType, idArg, stringArg, subscriptionField } = require('#prisma/nexus')
const Photon = require('#generated/photon')
const { nexusPrismaPlugin } = require('#generated/nexus-prisma')
const photon = new Photon()
const nexusPrisma = nexusPrismaPlugin({
photon: ctx => ctx.photon,
})
const Attack = objectType({
name: "Attack",
definition(t) {
t.model.id()
t.model.name()
t.model.damage()
}
})
const PokemonAttack = objectType({
name: "PokemonAttack",
definition(t) {
t.model.id()
t.model.special()
}
})
const Pokemon = objectType({
name: "Pokemon",
definition(t) {
t.model.id()
t.model.number()
t.model.name()
t.model.attacks()
}
})
const Query = objectType({
name: 'Query',
definition(t) {
t.crud.findManyPokemon({
alias: 'pokemons'
})
t.list.field('pokemon', {
type: 'Pokemon',
args: {
name: stringArg(),
},
resolve: (parent, { name }, ctx) => {
return ctx.photon.pokemon.findMany({
where: {
name
}
})
},
})
},
})
const Mutation = objectType({
name: 'Mutation',
definition(t) {
t.crud.createOnePokemon({ alias: 'addPokemon' })
},
})
const Subscription = subscriptionField('newPokemon', {
type: 'Pokemon',
subscribe: (parent, args, ctx) => {
return ctx.photon.$subscribe.pokemon()
},
resolve: payload => payload
})
const schema = makeSchema({
types: [Query, Mutation, Subscription, Pokemon, Attack, PokemonAttack, nexusPrisma],
outputs: {
schema: join(__dirname, '/schema.graphql')
},
typegenAutoConfig: {
sources: [
{
source: '#generated/photon',
alias: 'photon',
},
],
},
})
const server = new GraphQLServer({
schema,
context: request => {
return {
...request,
photon,
}
},
})
server.start(() => console.log(`🚀 Server ready at http://localhost:4000`))
The related part is the Subscription which I don't know why it's not working or how it's supposed to work.
I searched Github for this query which results in all projects using Subscriptions.
I also found out this commit in this project to be relevant to my answer. Posting the related code here for brevity:
import { subscriptionField } from 'nexus';
import { idArg } from 'nexus/dist/core';
import { Context } from './types';
export const PollResultSubscription = subscriptionField('pollResult', {
type: 'AnswerSubscriptionPayload',
args: {
pollId: idArg(),
},
subscribe(_: any, { pollId }: { pollId: string }, context: Context) {
// Subscribe to changes on answers in the given poll
return context.prisma.$subscribe.answer({
node: { poll: { id: pollId } },
});
},
resolve(payload: any) {
return payload;
},
});
Which is similar to what I do. But they do have AnswerSubscriptionPayload & I don't get any generated type that contains Subscription in it.
How do I solve this? I think I am doing everything right but it's still not working. Every example on GitHub is similar to above & even I am doing the same thing.
Any suggestions?
Edit: Subscriptions aren't implemented yet :(
I seem to have got this working despite subscriptions not being implemented. I have a working pubsub proof of concept based off the prisma2 boilerplate and Ben Awad's video tutorial https://youtu.be/146AypcFvAU . Should be able to get this up and running with redis and websockets to handle subscriptions until the prisma2 version is ready.
https://github.com/ryanking1809/prisma2_subscriptions
Subscriptions aren't implemented yet.
I've opened up an issue to track it.
I'll edit this answer as soon as it's implemented in Prisma 2.
The component:
The Input component with the onChange handler:
<Field
component={FormattedTextInput}
className={colMd113}
name={NAMES.VEHICLE_YEAR}
label={constants.VEHICLE_YEAR}
validate={[required, validator.validateYearOfVehicle]}
formatting="9999"
onChange={this.yearOnChange}
/>
The method:
constructor(props) {
super(props);
this.yearOnChange = this.yearOnChange.bind(this)
}
yearOnChange(event) {
if (event.target && event.target.value) {
const value = event.target.value;
this.setState({
year: value
});
}
}
The Test
it('yearOnChange method is called', function() {
const spy = jest.spyOn(wrapper.instance(), 'yearOnChange');
wrapper.update();
// const instance = wrapper.instance();
// console.log('instance', instance);
wrapper.simulate('change', {
target: {
name: 'vehicleYear',
value: '1999'
}
});
expect(spy).toHaveBeenCalled();
});
The Error
Vehicle Picker Component › yearOnChange method is called
expect(jest.fn()).toBeCalled()
Expected mock function to have been called, but it was not called.
50 | console.log(wrapper.instance())
51 |
> 52 | expect(spy).toBeCalled();
| ^
53 | });
This is what we see when I log the wrapper.instance()
VehiclePicker {
props: {},
context: {},
refs: {},
updater:
Updater {
_renderer:
ReactShallowRenderer {
_context: {},
_element: [Object],
_instance: [Circular],
_newState: null,
_rendered: [Object],
_rendering: false,
_forcedUpdate: false,
_updater: [Circular],
_dispatcher: [Object],
_workInProgressHook: null,
_firstWorkInProgressHook: null,
_isReRender: false,
_didScheduleRenderPhaseUpdate: false,
_renderPhaseUpdates: null,
_numberOfReRenders: 0 },
_callbacks: [] },
state:
{ year: '',
make: '',
makeArray: [],
model: '',
modelArray: [],
token: '' },
yearOnChange: [Function: bound yearOnChange],
makeOnChange: [Function: bound makeOnChange],
setState: [Function] }
UPDATE
With the following code, the expect(result).toEqual('1999') test works! But still the expect(spy).toHaveBeenCalled() does not :( How is it that when I instantiate the method yearOnChange and actually change the state in the component, that the spy still isn't detected to have been called?
it('yearOnChange method is called', function() {
const spy = jest.spyOn(VehiclePicker.prototype, 'yearOnChange');
wrapper.instance().forceUpdate();
const event = {
target: {
value: '1999'
}
};
wrapper.instance().yearOnChange(event);
wrapper.simulate('change', event);
const result = wrapper.state('year');
console.log('result', result); // result = 1999
expect(result).toEqual('1999');
expect(spy).toHaveBeenCalled();
});
Found great help from the answer here: Jest spyOn function called
This was the important step I was missing:
const instance = wrapper.instance()
const spy = jest.spyOn(instance, 'yearOnChange')
Updated working test with 2 working expects.
it('yearOnChange method is called', function() {
const instance = wrapper.instance(); // <-- Needed to do this here
const spy = jest.spyOn(instance, 'yearOnChange'); // <-- Then use instance here
wrapper.instance().forceUpdate();
const event = {
target: {
value: '1999'
}
};
wrapper.instance().yearOnChange(event);
wrapper.simulate('change', event);
const result = wrapper.state('year');
console.log('result', result); // result = 1999
expect(result).toEqual('1999');
expect(spy).toHaveBeenCalled();
});
You are spying and calling yearOnChange manually.
Try not calling wrapper.instance().yearOnChange(event);
Call the wrapper.instance().onChange event, or like you did, run the simulate('change') will be enough.
You could also try VehiclePicker.prototype.yearOnChange = jest.fn()
expect(VehiclePicker.prototype.yearOnChange).toBeCalled();
I have an angular application and I need to do some unit testing on some methods with Jasmine. IN this case I do a unit test on a select list. So that the select list will not be empty.
The method looks like this:
createStatusOptions(listValueoptions: OptionModel[], resources: any): OptionModel[] {
const processStatusOptions = listValueoptions.map(listValueOption => {
listValueOption.value = `${caseStatusEnum.inProgress}_${listValueOption.value}`;
listValueOption.selected = true;
return listValueOption;
});
const caseStatusEnumKeys = Object.keys(caseStatusEnum).filter(key => !isNaN(Number(key)));
const enumOptions = this.optionService.createOptions(
new ConfigOptionModel({ source: caseStatusEnumKeys, resources, resourcesModel: enumResourcesModel, isCustomEnum: true, }));
return [
this.getEnumOption(enumOptions, caseStatusEnum.submitted, true),
...processStatusOptions,
this.getEnumOption(enumOptions, caseStatusEnum.closed),
];
}
private getEnumOption(options: OptionModel[], enumType, isSelected = false): OptionModel {
const option = options.filter(enumOption => enumOption.value === `${enumType}`)[0];
option.selected = isSelected;
return option;
}
And I have the unit test like this:
it('should create status options when there ar list value options are provided', () => {
optionService.options = [
{
value: caseStatusEnum.submitted.toString(),
},
{
value: caseStatusEnum.inProgress.toString(),
},
{
value: caseStatusEnum.closed.toString(),
},
] as OptionModel[];
// tslint:disable-next-line:max-line-length
const result = service.createStatusOptions(optionService.options, [[103], [104], [105] ]);
console.log(result);
expect(result.length).toBe(2);
expect(result).toEqual([{ value: '103', selected: true }, { value: '105', selected: false }]);
});
But I get an error like this:
Services: CaseService > should create status options when there ar list value options are provided
TypeError: Cannot set property 'selected' of undefined
at <Jasmine>
at CaseService.getEnumOption (http://localhost:9878/src/app/case/src/services/case.service.ts?:130:9)
at CaseService.getEnumOption [as createStatusOptions] (http://localhost:9878/src/app/case/src/services/case.service.ts?:109:22)
at UserContext.<anonymous> (http://localhost:9878/src/app/case/src/services/case.service.spec.ts?:149:32)
at ZoneDelegate.../../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (http://localhost:9878/E:/Projects/Source/Repos/VLR/Web/vlrworkspace/node_modules/zone.js/dist/zone.js?:388:1)
at ProxyZoneSpec.push.../../node_modules/zone.js/dist/proxy.js.ProxyZoneSpec.onInvoke (http://localhost:9878/E:/Projects/Source/Repos/VLR/Web/vlrworkspace/node_modules/zone.js/dist/proxy.js?:128:1)
at ZoneDelegate.../../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (http://localhost:9878/E:/Projects/Source/Repos/VLR/Web/vlrworkspace/node_modules/zone.js/dist/zone.js?:387:1)
at Zone.../../node_modules/zone.js/dist/zone.js.Zone.run (http://localhost:9878/E:/Projects/Source/Repos/VLR/Web/vlrworkspace/node_modules/zone.js/dist/zone.js?:138:1)
at runInTestZone (http://localhost:9878/E:/Projects/Source/Repos/VLR/Web/vlrworkspace/node_modules/zone.js/dist/jasmine-patch.js?:145:1)
at UserContext.<anonymous> (http://localhost:9878/E:/Projects/Source/Repos/VLR/Web/vlrworkspace/node_modules/zone.js/dist/jasmine-patch.js?:160:1)
at <Jasmine>
So my question is: How to solve this?
Thank you
if I do this:
console.log(optionService.options);
I get this output:
Array(3)
0: {value: "103", selected: true}
1: {value: "104"}
2: {value: "105", selected: false}
length: 3
__proto__: Array(0)
this is the file:
import { fakeAsync, tick } from '#angular/core/testing';
import { FormServiceMock, MultiFileUploadServiceMock } from 'afw/forms/testing';
import { AfwHttp } from 'afw/generic-services';
import { AfwHttpMock, OptionServiceMock } from 'afw/generic-services/testing';
import { OptionModel, SearchResultModel } from 'afw/models';
import { FeedbackStoreServiceMock } from 'afw/store-services/testing';
import { RouterMock } from 'afw/testing';
import { PagingDataModel, TableSortDataModel } from 'afw/ui-components';
import { caseOwnerEnum, caseStatusEnum, caseTypeEnum, MultiFileUploadResourcesModel } from 'lr/models';
import { Observable, observable } from 'rxjs';
import { CaseTypeInfoModel } from 'support-shared/base/models';
import { CaseTypeInfoStoreServiceMock } from 'support-shared/base/services/case-type-info-store.service.mock';
import { CaseFormComponent } from '../case-base/src/case-form/case-form.component';
import { CaseBaseModel, CaseReferenceModel } from '../models';
import { CaseService } from './case.service';
let service: CaseService;
let afwHttpMock: AfwHttpMock;
// tslint:disable-next-line:prefer-const
let formServiceMock: FormServiceMock;
let multiFileUploadService: MultiFileUploadServiceMock;
let router: RouterMock;
let feedbackStoreService: FeedbackStoreServiceMock;
let optionService: OptionServiceMock;
let caseTypeInfoStoreService: CaseTypeInfoStoreServiceMock;
// tslint:disable-next-line:prefer-const
let component: CaseFormComponent;
fdescribe('Services: CaseService', () => {
beforeEach(() => {
afwHttpMock = new AfwHttpMock();
multiFileUploadService = new MultiFileUploadServiceMock();
router = new RouterMock();
feedbackStoreService = new FeedbackStoreServiceMock();
optionService = new OptionServiceMock();
caseTypeInfoStoreService = new CaseTypeInfoStoreServiceMock();
service = new CaseService(afwHttpMock as any, multiFileUploadService as any, router as any,
feedbackStoreService as any, optionService as any, caseTypeInfoStoreService as any);
});
it('should create an instance', () => {
expect(service).toBeTruthy();
});
it('should get case reference details', () => {
afwHttpMock.setupOnlyResponse({ type: caseTypeEnum.revisionRequest, details: { bsn: 'bsnLabel' } }, 200);
const d = service.getCaseReferenceDetails('spinnerMessage', { reference: '112314121', type: caseTypeEnum.revisionRequest });
d.subscribe(r => {
expect(r.details.length === 1);
expect(r.details[0].key).toBe('bsn');
expect(r.details[0].value).toBe('bsnLabel');
expect((r.details[0] as any).resourceKey).toBe('bsn');
});
afwHttpMock.returnSuccessResponse();
});
// tslint:disable-next-line:no-identical-functions
it('should get case reference details with full response', () => {
afwHttpMock.setupOnlyResponse({ body: { type: caseTypeEnum.revisionRequest, details: [{ key: 'hoi' }] } }, 200);
const d = service.getCaseReferenceDetailsFullResponse('spinnerMessage', { reference: '100001075', type: caseTypeEnum.revisionRequest });
// tslint:disable-next-line:no-commented-code
// tslint:disable-next-line:no-identical-functions
/* let result;
d.subscribe(r => {
result = r;
}); */
d.subscribe(r => {
expect(r.ok === true);
expect(r.body.details[0].key).toBe('hoi');
});
afwHttpMock.returnSuccessResponse();
// expect(result.ok === true);
// expect(result.)
});
// tslint:disable-next-line:no-commented-code
it('shoud get case type info configuration that is used on various views when snapshot exists', () => {
let result99: Observable<CaseTypeInfoModel[]>;
result99 = service.getCaseTypeInfo('spinner') as Observable<CaseTypeInfoModel[]>;
const response = [{ mock: 'mock' } as any];
service['caseTypeInfoSnapshot'] = response;
service.getCaseTypeInfo('spinner').subscribe(i => {
expect(i).toEqual(response);
});
});
// tslint:disable-next-line:no-identical-functions
it('shoud get case type info configuration that is used on various views when snapshot doesnt exists', () => {
let result99: Observable<CaseTypeInfoModel[]>;
const spy = spyOn(caseTypeInfoStoreService, 'addCaseTypeInfoToStore');
result99 = service.getCaseTypeInfo('spinner') as Observable<CaseTypeInfoModel[]>;
const response = [{ mock: 'mock' } as any];
service['caseTypeInfoSnapshot'] = response;
// caseTypeInfoStoreService..subscribe((result) => { expect(result).toBe(false); });
result99.subscribe((result) => {
expect(response).toEqual(response);
});
afwHttpMock.setupOnlyResponse(result99, 200);
afwHttpMock.returnSuccessResponse();
});
it('should create status options when no list value options are provided', () => {
optionService.options = [
{
value: caseStatusEnum.submitted.toString(),
},
{
value: caseStatusEnum.inProgress.toString(),
},
{
value: caseStatusEnum.closed.toString(),
},
] as OptionModel[];
// tslint:disable-next-line:no-commented-code
// const spy = spyOn(service, 'createStatusOptions');
const result = service.createStatusOptions([], {});
expect(result.length).toBe(2);
expect(result).toEqual([{ value: '103', selected: true }, { value: '105', selected: false }]);
// tslint:disable-next-line:no-commented-code
// const response = [{ mock: 'mock' } as any];
// expect(spy).toBe(result);
});
it('should create status options when there ar list value options are provided', () => {
optionService.options = [
{
value: caseStatusEnum.submitted.toString(),
},
{
value: caseStatusEnum.inProgress.toString(),
},
{
value: caseStatusEnum.closed.toString(),
},
] as OptionModel[];
// tslint:disable-next-line:max-line-length
const result = service.createStatusOptions(optionService.options, 103);
console.log(optionService.options);
expect(result.length).toBe(2);
expect(result).toEqual([{ value: '103', selected: true }, { value: '105', selected: false }]);
});
it('should get case reference without details', () => {
afwHttpMock.setupOnlyResponse({}, 200);
const spy = spyOn(afwHttpMock, 'post').and.callThrough();
const model = new CaseReferenceModel({ reference: '112314121', type: caseTypeEnum.revisionRequest });
const d = service.getCaseReferenceDetails('spinnerMessage', model);
d.subscribe(r => {
expect(r).toBeDefined();
});
expect(spy).toHaveBeenCalledWith('api/support/cases/get-reference-details', model, 'spinnerMessage');
afwHttpMock.returnSuccessResponse();
});
it('should add case reference without details', () => {
afwHttpMock.setupOnlyResponse({}, 200);
const spy = spyOn(afwHttpMock, 'post').and.callThrough();
const model = new CaseReferenceModel({ reference: '112314121', type: caseTypeEnum.revisionRequest });
const d = service.addCase('spinnerMessage', model as any);
d.subscribe(r => {
expect(r).toBeDefined();
});
expect(spy).toHaveBeenCalledWith('api/support/cases', model, 'spinnerMessage');
afwHttpMock.returnSuccessResponse();
});
it('should search for cases', () => {
const formModel: any = { makeQueryString: () => 'name=test' };
const pagingModel = new PagingDataModel({ currentPage: 10, itemsPerPage: 20 });
const sortModel = new TableSortDataModel({ columnName: 'kol', isDescending: false });
const spy = spyOn(afwHttpMock, 'get').and.callThrough();
const mockData = [
new CaseBaseModel({
id: 100000001,
type: caseTypeEnum.revisionRequest,
status: caseStatusEnum.inProgress,
substatus: 5266,
verdict: null,
owner: caseOwnerEnum.caseManager,
dateSubmitted: '02-02-2009',
dateClosed: '',
reference: 'aaa',
}),
];
const setupResponse = new SearchResultModel<CaseBaseModel>();
setupResponse.result = mockData;
setupResponse.totalResultCount = 27;
afwHttpMock.setupOnlyResponse(setupResponse, 200);
let response: SearchResultModel<CaseBaseModel>;
service.search(formModel, sortModel, pagingModel, 'spinnerText').subscribe(result => {
response = result;
});
afwHttpMock.returnOnlyResponse();
expect(spy).toHaveBeenCalledWith('api/support/cases?name=test&columnName=kol&isDescending=false¤tPage=10&itemsPerPage=20',
'spinnerText');
expect(response).toEqual(setupResponse);
expect(response.result[0].getResourceForStatus).toBeDefined();
});
it('should save documents', fakeAsync(() => {
const spy = spyOn(multiFileUploadService, 'syncFilesWithBackend').and.callThrough();
const spyRouter = spyOn(router, 'navigate').and.callThrough();
const spyFeedback = spyOn(feedbackStoreService, 'addSuccessMessageOnMainPortal');
service.saveDocuments(1, [{} as any], MultiFileUploadResourcesModel.keys, '../', { key: 'da', value: 'fa' });
expect(spy).toHaveBeenCalledWith('api/support/cases/1/documents', [{}],
MultiFileUploadResourcesModel.keys.bijlageToevoegenSpinnerTekst,
MultiFileUploadResourcesModel.keys.bijlageVerwijderenSpinnerTekst
);
tick();
expect(spyRouter).toHaveBeenCalledWith(['../']);
expect(spyFeedback).toHaveBeenCalled();
}));
it('should not save documents if there are no documents in array', fakeAsync(() => {
const spy = spyOn(multiFileUploadService, 'syncFilesWithBackend').and.callThrough();
const spyRouter = spyOn(router, 'navigate').and.callThrough();
const spyFeedback = spyOn(feedbackStoreService, 'addSuccessMessageOnMainPortal');
service.saveDocuments(1, [], MultiFileUploadResourcesModel.keys, '../', { key: 'da', value: 'fa' });
expect(spy).not.toHaveBeenCalled();
tick();
expect(spyRouter).toHaveBeenCalledWith(['../']);
expect(spyFeedback).toHaveBeenCalled();
}));
it('should save documents and report errors', fakeAsync(() => {
multiFileUploadService.setResponse([{}, { error: {} }]);
spyOn(multiFileUploadService, 'makeWarningMessageForUnsyncedFiles').and.returnValue('mock');
const spyRouter = spyOn(router, 'navigate').and.callThrough();
const spyFeedback = spyOn(feedbackStoreService, 'addWarningMessageOnMainPortal');
const spy = spyOn(multiFileUploadService, 'syncFilesWithBackend').and.callThrough();
service.saveDocuments(1, [{} as any], MultiFileUploadResourcesModel.keys, '../', { key: 'da', value: 'fa' });
expect(spy).toHaveBeenCalledWith('api/support/cases/1/documents', [{}],
MultiFileUploadResourcesModel.keys.bijlageToevoegenSpinnerTekst,
MultiFileUploadResourcesModel.keys.bijlageVerwijderenSpinnerTekst
);
tick();
expect(spyRouter).toHaveBeenCalledWith(['../']);
expect(spyFeedback).toHaveBeenCalled();
}));
it('should get case by id', () => {
const id = 66208014;
const setupResponse = new CaseBaseModel({
id,
dateSubmitted: '',
owner: caseOwnerEnum.caseManager,
reference: 'ksjhkjshdf',
status: caseStatusEnum.submitted,
type: caseTypeEnum.revisionRequest,
});
afwHttpMock.setupOnlyResponse(setupResponse, 200);
service.getCase(id, 'spinner').subscribe(r => {
expect(r).toEqual(setupResponse);
});
afwHttpMock.returnSuccessResponse();
});
it('edit the case with model', () => {
const spy = spyOn(service, 'editCase').and.callThrough();
const caseUpdate = new CaseBaseModel({
id: 100001075,
dateSubmitted: '',
owner: caseOwnerEnum.caseManager,
reference: 'ksjhkjshdf',
status: caseStatusEnum.submitted,
type: caseTypeEnum.revisionRequest,
});
service.editCase('spinner', caseUpdate);
expect(spy).toHaveBeenCalledWith('spinner', caseUpdate);
expect(caseUpdate.id).toEqual(100001075);
});
});
Based on what you showed so far, my guess is that the options parameter passed to getEnumOption() is undefined, which is causing the error you see. A quick console.log(options) within getEnumOption() would verify this.
If your code is working fine otherwise, but only failing in the test then I would make a second guess that you haven't properly mocked/spiedOn this.optionService.createOptions() since it sets up the options parameter that is potentially undefined. That would have been done earlier in the .spec file - if you post the whole file then that would help others who read your question to determine if this is the case.
Update with Stackblitz
I put all your code into a Stackblitz to test it. There was a lot of code I didn't have access to that I just guessed at the functionality of. However, I did discover a few things.
First, when you are testing you appear to be using the same variable both for the mock of the return expected by this.optionService.createOptions() as well as in the call to service.createStatusOptions() - which is likely not what you want to do.
Here is the code snippet I am talking about:
optionService.options = [
{
value: caseStatusEnum.submitted.toString(),
},
{
value: caseStatusEnum.inProgress.toString(),
},
{
value: caseStatusEnum.closed.toString(),
},
] as OptionModel[];
// tslint:disable-next-line:max-line-length
const result = service.createStatusOptions(optionService.options, [[103], [104], [105] ]);
When I called it this way in the Stackblitz I ran into a mutability issue - you are changing the data within the members of the objects inside the array, which will change it whereever that variable is accessed. To overcome this in the Stackblitz I made two copies of the data, one to use in the mock returnValue and another completely separate array of objects for the call to service.createStatusOptions(). Also, I am not familiar with the way you are mocking your service call, so I replaced it with a simple Jasmine spy in the Stackblitz.
Feel free to have a look at what I produced. Perhaps it will be helpful.
I have a collection and a mutation to add a new item to it. I haven't been able to get Relay Modern to update the UI after a successful mutation.
I've got a PaginationContainer setup with the following query: prop
{
query: graphql`
fragment ContactsList_query on WPQuery {
id
contacts: posts(
first: $count,
after: $cursor
post_type: $postType,
order: $order,
category_name: $categoryName
) #connection(key: "ContactsList_contacts" ) {
edges {
node {
id
...ContactListItem_contact
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
`
},
That fetches correctly. I've then got a mutation to add a contact to this list.
Neither the config RANGE_ADD or the updater: callback techniques work at all.
I'm triggering this mutation like so
onSave = (fields) => {
insertPost(
fields.toJS(),
this.props.query.id,
this.props.relay.environment
);
}
No errors, just nothing updates.
const mutation = graphql`
mutation InsertPostMutation(
$data: InsertPostInput!
) {
insert_post(input: $data) {
wp_query {
id
}
postEdge {
node {
id
title
}
}
}
}
`;
export default function insertPost(data, id, environment) {
const variables = {
data,
};
commitMutation(
environment,
{
mutation,
variables,
onCompleted: (response, errors) => {
console.log('Response received from server.')
},
onError: err => console.error(err),
configs: [{
type: 'RANGE_ADD',
parentID: id,
connectionInfo: [{
key: 'ContactsList_contacts',
rangeBehavior: 'append',
}],
edgeName: 'postEdge'
}],
// updater: (store) => {
// // const inspector = new RecordSourceInspector(store)
// const payload = store.getRootField('insert_post')
// const newEdge = payload.getLinkedRecord('postEdge')
// const proxy = store.get(id)
// // Conn is always undefined here
// const conn = ConnectionHandler.getConnection(proxy, 'ContactsList_contacts')
// ConnectionHandler.insertEdgeAfter(conn, newEdge)
// }
},
);
}
Well, I was able to fix this by changing the line
#connection(key: "ContactsList_contacts")
To
#connection(key: "ContactsList_contacts", filters: [])
Seems it couldn't find the connection otherwise...
https://facebook.github.io/relay/docs/pagination-container.html#connection-directive
Then using the updater function the connection was found.