Configured my store this way with redux toolkit for sure
const rootReducer = combineReducers({
someReducer,
systemsConfigs
});
const store = return configureStore({
devTools: true,
reducer: rootReducer ,
// middleware: [middleware, logger],
middleware: (getDefaultMiddleware) => getDefaultMiddleware({ thunk: false }).concat(middleware),
});
middleware.run(sagaRoot)
And thats my channel i am connecting to it
export function createSocketChannel(
productId: ProductId,
pair: string,
createSocket = () => new WebSocket('wss://somewebsocket')
) {
return eventChannel<SocketEvent>((emitter) => {
const socket_OrderBook = createSocket();
socket_OrderBook.addEventListener('open', () => {
emitter({
type: 'connection-established',
payload: true,
});
socket_OrderBook.send(
`subscribe-asdqwe`
);
});
socket_OrderBook.addEventListener('message', (event) => {
if (event.data?.includes('bids')) {
emitter({
type: 'message',
payload: JSON.parse(event.data),
});
//
}
});
socket_OrderBook.addEventListener('close', (event: any) => {
emitter(new SocketClosedByServer());
});
return () => {
if (socket_OrderBook.readyState === WebSocket.OPEN) {
socket_OrderBook.send(
`unsubscribe-order-book-${pair}`
);
}
if (socket_OrderBook.readyState === WebSocket.OPEN || socket_OrderBook.readyState === WebSocket.CONNECTING) {
socket_OrderBook.close();
}
};
}, buffers.expanding<SocketEvent>());
}
And here's how my saga connecting handlers looks like
export function* handleConnectingSocket(ctx: SagaContext) {
try {
const productId = yield select((state: State) => state.productId);
const requested_pair = yield select((state: State) => state.requested_pair);
if (ctx.socketChannel === null) {
ctx.socketChannel = yield call(createSocketChannel, productId, requested_pair);
}
//
const message: SocketEvent = yield take(ctx.socketChannel!);
if (message.type !== 'connection-established') {
throw new SocketUnexpectedResponseError();
}
yield put(connectedSocket());
} catch (error: any) {
reportError(error);
yield put(
disconnectedSocket({
reason: SocketStateReasons.BAD_CONNECTION,
})
);
}
}
export function* handleConnectedSocket(ctx: SagaContext) {
try {
while (true) {
if (ctx.socketChannel === null) {
break;
}
const events = yield flush(ctx.socketChannel);
const startedExecutingAt = performance.now();
if (Array.isArray(events)) {
const deltas = events.reduce(
(patch, event) => {
if (event.type === 'message') {
patch.bids.push(...event.payload.data?.bids);
patch.asks.push(...event.payload.data?.asks);
//
}
//
return patch;
},
{ bids: [], asks: [] } as SocketMessage
);
if (deltas.bids.length || deltas.asks.length) {
yield putResolve(receivedDeltas(deltas));
}
}
yield call(delayNextDispatch, startedExecutingAt);
}
} catch (error: any) {
reportError(error);
yield put(
disconnectedSocket({
reason: SocketStateReasons.UNKNOWN,
})
);
}
}
After Debugging I got the following:
The Thing is that when I Provide one Reducer to my store the channel works well and data is fetched where as when providing combinedReducers I am getting
an established connection from my handleConnectingSocket generator function
and an empty event array [] from
const events = yield flush(ctx.socketChannel) written in handleConnectedSocket
Tried to clarify as much as possible
ok so I start refactoring my typescript by changing the types, then saw all the places that break, there was a problem in my sagas.tsx.
Ping me if someone faced such an issue in the future
I have a code which execute request sequentially
try {
const results = [];
for await (let tc of testCases) {
const { data } = await axios.post("URL",
{
command_line_arguments: "",
compiler_options: "",
redirect_stderr_to_stdout: true,
source_code: source_code,
language_id,
stdin: tc.input,
expected_output: tc.output,
}
);
results.push({ text: tc.text, input: tc.input, output: tc.output, testType: tc.testType, ...data });
}
it works, but it is very slow.
I am looking to request all of them in parallel way.
Note: I have tries Promise all,Promise.allsettled, and Axios.all. Some how it didnt worked.
My solution:
const runTestCases = async (testCases: ITestCase[], source_code, language_id) => {
try {
const requests = createRequests(testCases, source_code, language_id);
const result = await Promise.all(requests.map(async (response) => {
const { data }:any = await response;
return data;
}));
return result;
} catch (error) {
throw new BadRequestError(error?.message);
}
};
/**
* Create array of request to run test cases in parallel
* #param testCases
* #param advance
* #returns
*/
const createRequests = (testCases: ITestCase[], source_code: string, language_id: string) => {
const requests = testCases.map((tc) => {
return () => axios.post(process.env.JUDGE0_HOST,{
redirect_stderr_to_stdout: true,
source_code: source_code,
language_id,stdin: tc.input,
expected_output: tc.output
})})
return requests;
};
output:
[ undefined, undefined ]
Am I doing wrong ?
Thanks in advance!
I am trying to write the test cases for below method :-
The below is the component code for adding the product
COMPONENT:
import { HttpClient } from '#angular/common/http';
import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '#angular/forms';
import { Observable } from 'rxjs';
import { Constants } from '../../../../../../utils/constants';
import { FileUploadService } from '../../../services/file-upload.service';
import { Component, EventEmitter, Input, OnInit, Output } from '#angular/core';
import { ManagePackageService } from '../../../services/manage-package.service';
import { DomSanitizer } from '#angular/platform-browser';
import { Package } from '../../../models/package.model';
import { ProductPackageMapping } from '../../../models/product-package-mapping.model';
import { Product } from '../../../models/product.model';
import { NotificationAlertService } from '../../../../shared/services/notification-alert.service';
import { ManageProductService } from '../../../services/manage-product.service';
import { DocumentDTO } from '../../../models/document-dto';
import { saveAs } from 'file-saver';
import { ConfirmationDialogService } from '../../../../shared/services/confirmation-dialog.service';
#Component({
selector: 'app-add-product',
templateUrl: './add-product.component.html',
styleUrls: ['./add-product.component.scss']
})
export class AddProductComponent implements OnInit {
productDetailForm: FormGroup;
addTitle: boolean = true;
isView: boolean = true;
submitted: boolean = false;
status: boolean = true;
check: boolean = false;
changevar: string;
#Input() id: Number;
#Output() changeIndicator = new EventEmitter<string>();
#Input() list: ProductPackageMapping;
#Output() dataLoaded = new EventEmitter<string>();
fileToUpload: File | null = null;
fileArray: Array<any> = [];
productData: any = [];
productDataTemp: any[];
fData = new FormData();
packagePlan: Array<any> = [];
productDto = new Product();
packageDto = new Package();
productPackageMappingDto = new ProductPackageMapping();
documentDto: Array<any> = [];
isDocId: boolean = false;
productForm: FormGroup;
activeStatus: boolean = true;
requiredFileType: string;
public NAME_MAX_LENGTH = 50;
isValidFormSubmitted: boolean;
#Input() allRolesFromParent: Product[] = [];
selectedFiles?: FileList;
message: string[] = [];
fileInfos?: Observable<any>;
documentList: Array<any> = [];
ppm: any;
fileUrl: any;
constructor(private http: HttpClient,
private formBuilder: FormBuilder,
private uploadService: FileUploadService,
private manageProduct: ManageProductService,
private managePackageService: ManagePackageService,
private sanitizer: DomSanitizer,
private notifyService: NotificationAlertService,
private confirmationDialogService: ConfirmationDialogService
) { }
ngOnInit(): void {
this.createForm();
this.fileInfos = this.uploadService.getFiles();
this.fData = new FormData();
this.subscriptionPackages()
}
closeModal() {
this.status = true;
this.check = false;
this.changevar = 'cancel';
this.changeIndicator.emit(this.changevar);
this.productForm.reset();
this.fData.delete('ppm');
this.fData.delete('file');
this.emit();
}
closeEditModel() {
this.status = true;
this.documentList = [];
this.changevar = "cancel";
this.changeIndicator.emit(this.changevar);
this.addTitle = true;
this.productForm.reset();
this.fData.delete("ppm");
this.fData.delete("file");
this.emit();
}
onChangeSwitch(event) {
if (event.target.checked == true) {
this.activeStatus = true;
} else {
this.activeStatus = false;
}
}
createForm() {
this.productForm = new FormGroup({
name: new FormControl(this.productDto.name, [
Validators.required,
Validators.maxLength(this.NAME_MAX_LENGTH),
Validators.pattern(Constants.NO_WHITE_SPACE_PATTERN),
]),
url: new FormControl(this.productDto.demoURL, Validators.required),
version: new FormControl(this.productDto.productVersion, Validators.required),
projectType: new FormControl(this.productDto.projectType, Validators.required),
plansName: new FormControl(this.packageDto.id, Validators.required),
desc: new FormControl(this.productDto.productDescription, Validators.required),
active: new FormControl(this.productDto.active, Validators.required),
documents: this.formBuilder.array([]),
});
}
ngOnChanges() {
this.productData = this.list;
if (this.id) {
this.addTitle = false;
this.productDataTemp = this.productData.filter((vl) => (this.id == vl.id));
this.productDataTemp.forEach(obj => {
this.productDto.ppmId = obj.ppmId;
this.productDto.id = obj.id;
this.productDto.name = obj.name;
this.productDto.demoURL = obj.demoURL;
this.productDto.productDescription = obj.productDescription;
this.productDto.projectType = obj.type;
this.productDto.active = obj.active;
this.productDto.productVersion = obj.version;
this.packageDto.id = obj.pkgInfo.id;
this.documentList = obj.listDocuments
})
this.createForm();
} else {
this.productDto = new Product();
this.packageDto = new Package();
this.documentDto = [];
this.documentList = [];
}
this.documentList.length == 0 ? this.isDocId = false : this.isDocId = true;
}
get f() {
return this.productForm.controls;
}
choosePackages(e) {
}
subscriptionPackages() {
this.managePackageService.getPackages().subscribe(
(response) => {
this.packagePlan = response;
},
(httpErrorRes) => {
}
);
}
get documentsFormArray(): FormArray {
return this.f['documents'] as FormArray;
}
addDocument() {
if (this.documentsFormArray.length < 5) {
this.documentsFormArray.push(this.formBuilder.group({
id: new FormControl(''),
docName: new FormControl('', Validators.required),
docType: new FormControl('', Validators.required),
attachment: new FormControl('', Validators.required)
}))
}
}
deleteRow(i: number) {
if (this.id) {
delete this.fileArray[i];
this.documentsFormArray.removeAt(i);
this.fileArray.splice(i, 1);
}
else {
delete this.documentsFormArray[i];
this.documentsFormArray.removeAt(i);
this.fileArray.splice(i, 1);
}
}
getFiles(fileArray) {
this.fileArray.forEach(files => {
this.fData.append("file", files);
})
}
selectFiles(event): void {
this.selectedFiles = event.target.files;
}
onFormSubmit() {
this.submitted = true;
if (this.fileArray.length > 0) {
this.getFiles(this.fileArray);
}
if (this.productForm.value.id === null) {
this.productDto.id = null;
}
this.productDto.name = this.productForm.value.name;
this.productDto.demoURL = this.productForm.value.url;
this.productDto.productVersion = this.productForm.value.version;
this.productDto.projectType = this.productForm.value.projectType;
this.productDto.productDescription = this.productForm.value.desc;
this.productDto.active = this.productForm.value.active;
this.packageDto.id = this.productForm.value.plansName;
if (this.documentsFormArray && this.documentsFormArray.value && this.documentsFormArray.value.length > 0) {
this.documentsFormArray.value.forEach(element => {
this.documentDto.push(element);
});
}
this.productPackageMappingDto.id = this.productDto.ppmId ? this.productDto.ppmId : null;
this.productPackageMappingDto.products = this.productDto;
this.productPackageMappingDto.packages = this.packageDto;
this.productPackageMappingDto.document = this.documentDto;
this.ppm = new Blob([JSON.stringify(this.productPackageMappingDto)], { type: "application/json" });
this.fData.has("file") ? true : this.fData.append("file", '');
this.fData.append("ppm", this.ppm);
this.confirmationDialogService.confirm('Are you sure ?', 'Do you really want to Activate/ Deactivate Package ?')
.then((confirmed) => {
if (confirmed) {
this.manageProduct.createProduct(this.fData).subscribe(
(response) => {
this.notifyService.showSuccess("Data saved successfully !!", "Success")
this.closeModal();
this.fData.delete("ppm");
this.fData.delete("file");
this.productDto = new Product();
this.packageDto = new Package();
this.documentDto = [];
this.documentList = [];
this.fileArray = [];
this.emit();
},
(httpErrorRes) => {
this.fData.delete("ppm");
this.fData.delete("file");
this.notifyService.showError(httpErrorRes.error, "Error");
}
);
}
else {
this.fData.delete("ppm");
this.fData.delete("file");
}
})
}
upload(event: any) {
let files = event.target.files[0];
this.fileArray.push(files);
}
downloadFile(fileData: DocumentDTO): void {
this.manageProduct.download(fileData.fileName)
.subscribe(blob => saveAs(blob, fileData.fileName));
}
emit() {
this.dataLoaded.emit('AddProductComponent')
}
}
The below is the spec file for the above component
COMPONENT.SPEC.TS
import { HttpClientTestingModule } from '#angular/common/http/testing';
import { ComponentFixture, TestBed } from '#angular/core/testing';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
import { NgSelectModule } from '#ng-select/ng-select';
import { TranslateModule } from '#ngx-translate/core';
import { ToastrModule } from 'ngx-toastr';
import { Observable, of, throwError } from 'rxjs';
import { AppConfig } from '../../../../../app.config';
import { ConfirmationDialogService } from '../../../../configurations/services/confirmation-dialog.service';
import { NotificationAlertService } from '../../../../shared/services/notification-alert.service';
import { DocumentDTO } from '../../../models/document-dto';
import { ManagePackageService } from '../../../services/manage-package.service';
import { ManageProductService } from '../../../services/manage-product.service';
import { AddProductComponent } from './add-product.component';
describe('AddProductComponent', () => {
let component: AddProductComponent;
let fixture: ComponentFixture<AddProductComponent>;
let packageServiceStub = jasmine.createSpyObj('ManagePackageService', ['getPackages']);
let confirmationDialougeStub = jasmine.createSpyObj('ConfirmationDialogService', ['confirm']);
let manageProductStub = jasmine.createSpyObj('ManageProductService', ['createProduct','download']);
let notificationStub = jasmine.createSpyObj('NotificationAlertService', ['showSuccess', 'showError']);
let fileData = new DocumentDTO()
class MockUserService {
getPackages() {
return [{'name':'basic', 'id':1}, {'name':'advance', 'id':2}, {'name':'premium', 'id':3}];
}
}
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [HttpClientTestingModule,ReactiveFormsModule,FormsModule,ToastrModule.forRoot(),
TranslateModule.forRoot(), NgSelectModule],
declarations: [ AddProductComponent ],
providers :[AppConfig,
{ provide: ManageProductService, useValue: manageProductStub },
{ provide: ManagePackageService, useValue: packageServiceStub }]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(AddProductComponent);
component = fixture.componentInstance;
const mockpackageResponse = [];
packageServiceStub.getPackages.and.returnValue(of(mockpackageResponse));
component.activeStatus = true;
component.productDataTemp = [{'ppmId': 2, 'id': 2, 'name': 'ttvrtv', 'productDescription': 'vttvt', 'projectType': null}]
component.productData = [{'ppmId': 1, 'id': 1, 'name': 'tvrtv', 'productDescription': 'vtvt', 'projectType': null},
{'ppmId': 2, 'id': 2, 'name': 'ttvrtv', 'productDescription': 'vttvt', 'projectType': null}]
component.id = 2;
component.fileArray = ['dfdfdf','dfdsdf']
component.packagePlan = [{'name':'basic', 'id':1}, {'name':'advance', 'id':2}, {'name':'premium', 'id':3}];
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should create closeModal()', () => {
const eventTrue = {
target: {
checked: true,
}
};
const eventFalse = {
target: {
checked: false,
}
};
component.closeModal();
component.closeEditModel();
component.onChangeSwitch(eventTrue)
component.onChangeSwitch(eventFalse)
});
// it('should create ngOnChanges', () => {
// component.ngOnChanges();
// });
it('should create choosePackages', () => {
const event = {};
component.choosePackages(event);
});
it('should create subscriptionPackages()', () => {
component.subscriptionPackages();
expect(component.packagePlan).toBeTruthy();
});
// it('should handle error subscriptionPackages', () => {
// spyOn(window, 'alert');
// packageServiceStub.getPackages.and.returnValue(throwError({ error: 'some error'}));
// component.subscriptionPackages();
// });
it('should create addDocument()', () => {
component.addDocument();
});
it('should create deleteRow(i: number)', () => {
component.id = 1;
component.deleteRow(1);
});
it('should create deleteRow(i: number) nullity check', () => {
component.id = null;
component.deleteRow(null);
});
it('should create selectFiles', () => {
const eventSelectFiles = {
target: {
files: 'ss',
}
};
component.selectFiles(eventSelectFiles);
});
it('should create onFormSubmit length>0', () => {
component.fileArray.length = 2;
component.onFormSubmit();
});
it('should create onFormSubmit nullity check', () => {
component.productForm.value.id = null
component.onFormSubmit();
});
// it('should create onFormSubmit else part', (done) => {
// const confirmationResponse = {}; // Keep is as your response
// let spy = spyOn( confirmationDialougeStub,'confirm').and.returnValue(Promise.resolve(true));
// // fixture.whenStable().then(confirmed => {
// // fixture.detectChanges();
// // component.onFormSubmit();
// // })
// spy.calls.mostRecent().returnValue.then(() => {
// fixture.detectChanges();
// //component.onFormSubmit();
// done();
// });
// });
// it('should create onFormSubmit else part', () => {
// confirmationDialougeStub.confirm.and.returnValue({
// closePromise : {
// then : function(callback) {
// callback({value: true});
// }
// }
// });
// });
it('should create upload download', () => {
const eventFile = {
target: {
files: true,
}
};
component.upload(eventFile);
});
});
PROBLEM :- I have some below pointers regarding Jasmine and trying to figure it out the way to achieve the same.
I am not able to figured out the way to cover or test what the promises return
this.confirmationDialogService.confirm('Are you sure ?', 'Do you really want to Activate/ Deactivate Package ?')
.then((confirmed) => {
In the code coverage, the above lines are not covered and I don't know what went wrong, I have tried so many ways and referred many of the posts from stackoverflow itself but that weren't work for my use case.
how to write test cases for a method having foreach(), filter(), map()
how to write test cases for a method having observables, subscribe and promises
Please suggest the best practices.
Your component is quite long, I will show you how to you can cover the following lines with Promises and Observables.
this.confirmationDialogService.confirm('Are you sure ?', 'Do you really want to Activate/ Deactivate Package ?')
.then((confirmed) => {
if (confirmed) {
this.manageProduct.createProduct(this.fData).subscribe(
Make the following changes:
// dialog is spelt wrong here
let confirmationDialogStub = jasmine.createSpyObj('ConfirmationDialogService', ['confirm']);
....
providers: [
...
// provide the mock for confiramtion dialog service
{ provide: ConfirmationDialogService, usevalue: confirmationDialogStub },
{ provide: ManageProductService, useValue: manageProductStub },
{ provide: ManagePackageService, useValue: packageServiceStub }
],
// fakeAsync because we need tick (wait for promises to resolve before asserting)
it('does abc', fakeAsync(() => {
// mock the value for confirmation with a promise
confirmationDialogStub.confirm.and.returnValue(Promise.resovle(true));
manageProductStub.createProduct.and.returnValue(of({/* mock however you wish */}));
// call the method
component.onFormSubmit();
// wait for all promises to resolve with tick
tick();
// do your assertions
}));
For forEach, filter, map, make sure you mock an array. That the array is there.
That being said, I highly recommend you check out the following resources, they will help you a lot.
https://testing-angular.com/
^ A well written e-book.
https://www.pluralsight.com/courses/unit-testing-angular
^ A really good class on unit testing in Angular.
My Scenario
I'm using Google Drive API to create a file and to get a list of files.
My problem
1. No matter what value I put in my access_token the API keeps working
2. If I change the order of events and I call createDriveFile before I call listDriveFiles I get this error:
Error: Invalid Credentials
at Gaxios._request (/Users/tamirklein/superquery/bd/lambda/node_modules/googleapis-common/node_modules/google-auth-library/node_modules/gaxios/src/gaxios.ts:109:15)
at
at process._tickDomainCallback (internal/process/next_tick.js:228:7)
My code
if (!global._babelPolyfill) {
var a = require("babel-polyfill")
}
import {google} from 'googleapis'
describe('Run query with API', async () => {
it('check Drive APIs', async () => {
process.env.x_region = 'us-east-1';
let result = await test('start')
})
async function test(p1) {
let auth = getBasicAuthObj();
auth.setCredentials({
access_token: "anyValueWork",
refresh_token: "Replace With a valid refresh Token"
});
let fileList = await listDriveFiles(auth);
let newFile = await createDriveFile(auth);
}
async function listDriveFiles(auth) {
return new Promise((resolved) => {
const {google} = require('googleapis');
const drive = google.drive({version: 'v3', auth});
drive.files.list({
pageSize: 10,
fields: 'nextPageToken, files(id, name)',
q: 'trashed=false'
}, (err, res) => {
if (err) {
console.log('The API returned an error: ' + err);
resolved([err, null]);
} else {
const files = res.data.files;
if (files.length) {
console.log(`We fetched ${files.length} Files`);
// files.map((file) => {
// console.log(`${file.name} (${file.id})`);
// });
} else {
console.log('No files found.');
}
resolved([err, res]);
}
});
});
}
async function createDriveFile(auth) {
return new Promise(async (resolved) => {
//const fs = require('fs');
const {google} = require('googleapis');
const drive = google.drive({version: 'v3', auth});
let data = {
value: 'value'
};
let fileName = 'fileName.txt';
let fileMetadata = {
'name': fileName
};
// create buffer
let stream = require('stream');
let bufferStream = new stream.PassThrough();
bufferStream.end(Buffer.from(JSON.stringify(data)));
let media = {
mimeType: 'application/json',
body: bufferStream // fs.createReadStream("test.txt") //bufferStream //
};
drive.files.create({
resource: fileMetadata,
media: media,
fields: 'id'
}, function (err, file) {
if (err) {
// Handle error
console.error("Error: savePasswordInDrive" + err);
} else {
console.log('File Id: ', file.data.id);
}
resolved([err, file]);
});
})
}
async function _wait(milliseconds) {
return new Promise(resolved => {
setTimeout(() => {
resolved()
}, milliseconds)
})
}
/**
* Create oAuth object
* #returns {OAuth2Client}
*/
function getBasicAuthObj() {
let clientId = 'Replace With a valid clientId';
let clientSecret = 'Replace With a valid clientSecret';
let redirectUrl = 'URL';
return new google.auth.OAuth2(
clientId,
clientSecret,
redirectUrl
)
}
})
Any ideas on how to resolve this?
I have written integration tests for graphql-js subscriptions, which are showing weird behavior.
My graphq-js subscription works perfectly in GraphiQL. But when the same subscriptions is called from unit test, it fails.
Ggraphql-Js object, with resolve function and subscribe function
return {
type: outputType,
args: {
input: {type: new GraphQLNonNull(inputType)},
},
resolve(payload, args, context, info) {
const clientSubscriptionId = (payload) ? payload.subscriptionId : null;
const object = (payload) ? payload.object : null;
var where = null;
var type = null;
var target = null;
if (object) {
where = (payload) ? payload.object.where : null;
type = (payload) ? payload.object.type : null;
target = (payload) ? payload.object.target : null;
}
return Promise.resolve(subscribeAndGetPayload(payload, args, context, info))
.then(payload => ({
clientSubscriptionId, where, type, target, object: payload.data,
}));
},
subscribe: withFilter(
() => pubSub.asyncIterator(modelName),
(payload, variables, context, info) => {
const subscriptionPayload = {
clientSubscriptionId: variables.input.clientSubscriptionId,
remove: variables.input.remove,
create: variables.input.create,
update: variables.input.update,
opts: variables.input.options,
};
subscriptionPayload.model = model;
try {
pubSub.subscribe(info.fieldName, null, subscriptionPayload);
} catch (ex) {
console.log(ex);
}
return true;
}
),
};
Subscription query
subscription {
Customer(input: {create: true, clientSubscriptionId: 112}) {
customer {
id
name
age
}
}
}
Mutation query
mutation {
Customer {
CustomerCreate (input:{data:{name:"Atif 50", age:50}}) {
obj {
id
name
}
}
}
}
Integration Test
'use strict';
const ws = require('ws');
const { SubscriptionClient } = require('subscriptions-transport-ws');
const { ApolloClient } = require('apollo-client');
const { HttpLink } = require('apollo-link-http');
const { InMemoryCache } = require('apollo-cache-inmemory');
const Promise = require('bluebird');
const expect = require('chai').expect;
const chai = require('chai').use(require('chai-http'));
const server = require('../server/server');
const gql = require('graphql-tag');
let apollo;
let networkInterface;
const GRAPHQL_ENDPOINT = 'ws://localhost:5000/subscriptions';
describe('Subscription', () => {
before(async () => {
networkInterface = new SubscriptionClient(
GRAPHQL_ENDPOINT, { reconnect: true }, ws);
apollo = new ApolloClient({
networkInterface ,
link: new HttpLink({ uri: 'http://localhost:3000/graphql' }),
cache: new InMemoryCache()
});
});
after(done => {
networkInterface.close() ;
});
it('subscription', async () => {
const client = () => apollo;
// SUBSCRIBE and make a promise
const subscriptionPromise = new Promise((resolve, reject) => {
client().subscribe({
query: gql`
subscription {
Customer(input: {create: true,
clientSubscriptionId: 112,
options: {where: {age: 50}}}) {
customer {
name
}
}
}
`
}).subscribe({
next: resolve,
error: reject
});
});
let execGraphQL;
// MUTATE
await execGraphQL(
`mutation {
Customer {
CustomerCreate (input:{data:{name:"Atif 21", age:50}}) {
obj {
id
name
}
}
}
}`
);
// ASSERT SUBSCRIPTION RECEIVED EVENT
expect(await subscriptionPromise).to.deep.equal({});
});
});
Issue Here
When test in run, payload in the resolve function contains global data, where as it should contain the subscription payload. So the code breaks.