diff --git a/lib/process-services-cloud/.storybook/tsconfig.json b/lib/process-services-cloud/.storybook/tsconfig.json index 30f9f5e443..83c6a0ca45 100644 --- a/lib/process-services-cloud/.storybook/tsconfig.json +++ b/lib/process-services-cloud/.storybook/tsconfig.json @@ -6,5 +6,5 @@ }, "exclude": ["../**/*.spec.ts" ], - "include": ["../src/**/*", "*.js", "../../core/feature-flags"] + "include": ["../src/**/*", "*.js"] } diff --git a/lib/process-services-cloud/src/lib/process/process-filters/services/process-filter-cloud.service.spec.ts b/lib/process-services-cloud/src/lib/process/process-filters/services/process-filter-cloud.service.spec.ts index 2d76b472dd..df1abc0451 100644 --- a/lib/process-services-cloud/src/lib/process/process-filters/services/process-filter-cloud.service.spec.ts +++ b/lib/process-services-cloud/src/lib/process/process-filters/services/process-filter-cloud.service.spec.ts @@ -32,7 +32,6 @@ import { import { ProcessFilterCloudModel } from '../models/process-filter-cloud.model'; import { IdentityUserService } from '../../../people/services/identity-user.service'; import { NotificationCloudService } from '../../../services/notification-cloud.service'; -import { provideMockFeatureFlags } from '@alfresco/adf-core/feature-flags'; describe('ProcessFilterCloudService', () => { let service: ProcessFilterCloudService; @@ -53,10 +52,7 @@ describe('ProcessFilterCloudService', () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [ProcessServiceCloudTestingModule], - providers: [ - { provide: PROCESS_FILTERS_SERVICE_TOKEN, useClass: LocalPreferenceCloudService }, - provideMockFeatureFlags({ ['studio-ws-graphql-subprotocol']: false }) - ] + providers: [{ provide: PROCESS_FILTERS_SERVICE_TOKEN, useClass: LocalPreferenceCloudService }] }); service = TestBed.inject(ProcessFilterCloudService); @@ -72,7 +68,7 @@ describe('ProcessFilterCloudService', () => { }); it('should create processfilter key by using appName and the username', (done) => { - service.getProcessFilters('mock-appName').subscribe((res: ProcessFilterCloudModel[]) => { + service.getProcessFilters('mock-appName').subscribe((res: any) => { expect(res).toBeDefined(); expect(getCurrentUserInfoSpy).toHaveBeenCalled(); done(); @@ -141,7 +137,7 @@ describe('ProcessFilterCloudService', () => { it('should create the process filters in case the filters are not exist in the user preferences', (done) => { getPreferencesSpy.and.returnValue(of(fakeProcessCloudFilterWithDifferentEntries)); - service.getProcessFilters('mock-appName').subscribe((res: ProcessFilterCloudModel[]) => { + service.getProcessFilters('mock-appName').subscribe((res: any) => { expect(res).toBeDefined(); expect(res).not.toBeNull(); expect(res.length).toBe(3); @@ -247,7 +243,6 @@ describe('ProcessFilterCloudService', () => { it('should reset filters to default values', async () => { const changedFilter = new ProcessFilterCloudModel(fakeProcessCloudFilters[0]); changedFilter.processDefinitionKey = 'modifiedProcessDefinitionKey'; - // eslint-disable-next-line @typescript-eslint/no-explicit-any spyOn(service, 'defaultProcessFilters').and.returnValue(fakeProcessCloudFilters); await service.resetProcessFilterToDefaults('mock-appName', changedFilter).toPromise(); diff --git a/lib/process-services-cloud/src/lib/services/notification-cloud.service.spec.ts b/lib/process-services-cloud/src/lib/services/notification-cloud.service.spec.ts index 3139b39373..9374153402 100644 --- a/lib/process-services-cloud/src/lib/services/notification-cloud.service.spec.ts +++ b/lib/process-services-cloud/src/lib/services/notification-cloud.service.spec.ts @@ -18,12 +18,17 @@ import { TestBed } from '@angular/core/testing'; import { ProcessServiceCloudTestingModule } from '../testing/process-service-cloud.testing.module'; import { NotificationCloudService } from './notification-cloud.service'; -import { WebSocketService } from './web-socket.service'; -import { provideMockFeatureFlags } from '@alfresco/adf-core/feature-flags'; +import { Apollo } from 'apollo-angular'; describe('NotificationCloudService', () => { let service: NotificationCloudService; - let wsService: WebSocketService; + let apollo: Apollo; + let apolloCreateSpy: jasmine.Spy; + let apolloSubscribeSpy: jasmine.Spy; + + const useMock: any = { + subscribe: () => {} + }; const queryMock = ` subscription { @@ -38,25 +43,39 @@ describe('NotificationCloudService', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [ProcessServiceCloudTestingModule], - providers: [WebSocketService, provideMockFeatureFlags({ ['studio-ws-graphql-subprotocol']: false })] + imports: [ProcessServiceCloudTestingModule] }); service = TestBed.inject(NotificationCloudService); - wsService = TestBed.inject(WebSocketService); + apollo = TestBed.inject(Apollo); + + service.appsListening = []; + apolloCreateSpy = spyOn(apollo, 'createNamed'); + apolloSubscribeSpy = spyOn(apollo, 'use').and.returnValue(useMock); }); - it('should call getSubscription with the correct parameters', () => { - const getSubscriptionSpy = spyOn(wsService, 'getSubscription').and.callThrough(); + it('should not create more than one websocket per app if it was already created', () => { + service.makeGQLQuery('myAppName', queryMock); + expect(service.appsListening.length).toBe(1); + expect(service.appsListening[0]).toBe('myAppName'); service.makeGQLQuery('myAppName', queryMock); + expect(service.appsListening.length).toBe(1); + expect(service.appsListening[0]).toBe('myAppName'); - expect(getSubscriptionSpy).toHaveBeenCalledWith({ - apolloClientName: 'myAppName', - wsUrl: 'myAppName/notifications', - httpUrl: 'myAppName/notifications/graphql', - subscriptionOptions: { - query: jasmine.any(Object) - } - }); + expect(apolloCreateSpy).toHaveBeenCalledTimes(1); + expect(apolloSubscribeSpy).toHaveBeenCalledTimes(2); + }); + + it('should create new websocket if it is subscribing to new app', () => { + service.makeGQLQuery('myAppName', queryMock); + expect(service.appsListening.length).toBe(1); + expect(service.appsListening[0]).toBe('myAppName'); + + service.makeGQLQuery('myOtherAppName', queryMock); + expect(service.appsListening.length).toBe(2); + expect(service.appsListening[1]).toBe('myOtherAppName'); + + expect(apolloCreateSpy).toHaveBeenCalledTimes(2); + expect(apolloSubscribeSpy).toHaveBeenCalledTimes(2); }); }); diff --git a/lib/process-services-cloud/src/lib/services/notification-cloud.service.ts b/lib/process-services-cloud/src/lib/services/notification-cloud.service.ts index 1646b3c97d..afb1cd3bbe 100644 --- a/lib/process-services-cloud/src/lib/services/notification-cloud.service.ts +++ b/lib/process-services-cloud/src/lib/services/notification-cloud.service.ts @@ -15,24 +15,101 @@ * limitations under the License. */ -import { gql } from '@apollo/client/core'; +import { Apollo } from 'apollo-angular'; +import { HttpLink } from 'apollo-angular/http'; +import { split, gql, InMemoryCache, ApolloLink, InMemoryCacheConfig } from '@apollo/client/core'; +import { WebSocketLink } from '@apollo/client/link/ws'; +import { onError } from '@apollo/client/link/error'; +import { getMainDefinition } from '@apollo/client/utilities'; import { Injectable } from '@angular/core'; -import { WebSocketService } from './web-socket.service'; +import { AuthenticationService } from '@alfresco/adf-core'; +import { BaseCloudService } from './base-cloud.service'; +import { AdfHttpClient } from '@alfresco/adf-core/api'; @Injectable({ providedIn: 'root' }) -export class NotificationCloudService { - constructor(private readonly webSocketService: WebSocketService) {} +export class NotificationCloudService extends BaseCloudService { + appsListening = []; + + constructor(public apollo: Apollo, private http: HttpLink, private authService: AuthenticationService, protected adfHttpClient: AdfHttpClient) { + super(adfHttpClient); + } + + private get webSocketHost() { + return this.contextRoot.split('://')[1]; + } + + private get protocol() { + return this.contextRoot.split('://')[0] === 'https' ? 'wss' : 'ws'; + } + + initNotificationsForApp(appName: string) { + if (!this.appsListening.includes(appName)) { + this.appsListening.push(appName); + const httpLink = this.http.create({ + uri: `${this.getBasePath(appName)}/notifications/graphql` + }); + + const webSocketLink = new WebSocketLink({ + uri: `${this.protocol}://${this.webSocketHost}/${appName}/notifications/ws/graphql`, + options: { + reconnect: true, + lazy: true, + connectionParams: { + kaInterval: 2000, + // eslint-disable-next-line @typescript-eslint/naming-convention + 'X-Authorization': 'Bearer ' + this.authService.getToken() + } + } + }); + + const link = split( + ({ query }) => { + const definition = getMainDefinition(query); + return definition.kind === 'OperationDefinition' && definition.operation === 'subscription'; + }, + webSocketLink, + httpLink + ); + + const errorLink = onError(({ graphQLErrors, operation, forward }) => { + if (graphQLErrors) { + for (const err of graphQLErrors) { + switch (err.extensions.code) { + case 'UNAUTHENTICATED': { + const oldHeaders = operation.getContext().headers; + operation.setContext({ + headers: { + ...oldHeaders, + // eslint-disable-next-line @typescript-eslint/naming-convention + 'X-Authorization': 'Bearer ' + this.authService.getToken() + } + }); + forward(operation); + break; + } + default: + break; + } + } + } + }); + + this.apollo.createNamed(appName, { + link: ApolloLink.from([errorLink, link]), + cache: new InMemoryCache({ merge: true } as InMemoryCacheConfig), + defaultOptions: { + watchQuery: { + errorPolicy: 'all' + } + } + }); + } + } makeGQLQuery(appName: string, gqlQuery: string) { - return this.webSocketService.getSubscription({ - apolloClientName: appName, - wsUrl: `${appName}/notifications`, - httpUrl: `${appName}/notifications/graphql`, - subscriptionOptions: { - query: gql(gqlQuery) - } - }); + this.initNotificationsForApp(appName); + return this.apollo.use(appName).subscribe({ query: gql(gqlQuery) }); } } diff --git a/lib/process-services-cloud/src/lib/services/public-api.ts b/lib/process-services-cloud/src/lib/services/public-api.ts index 40684e03a6..5da40b1da7 100644 --- a/lib/process-services-cloud/src/lib/services/public-api.ts +++ b/lib/process-services-cloud/src/lib/services/public-api.ts @@ -24,4 +24,3 @@ export * from './form-fields.interfaces'; export * from './base-cloud.service'; export * from './task-list-cloud.service.interface'; export * from './variable-mapper.sevice'; -export * from './web-socket.service'; diff --git a/lib/process-services-cloud/src/lib/services/web-socket.service.spec.ts b/lib/process-services-cloud/src/lib/services/web-socket.service.spec.ts deleted file mode 100644 index 4ca6d691e3..0000000000 --- a/lib/process-services-cloud/src/lib/services/web-socket.service.spec.ts +++ /dev/null @@ -1,135 +0,0 @@ -/*! - * @license - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { AppConfigService, AuthenticationService } from '@alfresco/adf-core'; -import { TestBed } from '@angular/core/testing'; -import { Apollo, gql } from 'apollo-angular'; -import { of, Subject } from 'rxjs'; -import { WebSocketService } from './web-socket.service'; -import { SubscriptionOptions } from '@apollo/client/core'; -import { FeaturesServiceToken, IFeaturesService, provideMockFeatureFlags } from '@alfresco/adf-core/feature-flags'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; - -describe('WebSocketService', () => { - let service: WebSocketService; - let featureService: IFeaturesService; - const onLogoutSubject: Subject = new Subject(); - - const apolloMock = jasmine.createSpyObj('Apollo', ['use', 'createNamed']); - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - { - provide: Apollo, - useValue: apolloMock - }, - { - provide: AppConfigService, - useValue: { - get: () => 'wss://testHost' - } - }, - { - provide: AuthenticationService, - useValue: { - getToken: () => 'testToken', - onLogout: onLogoutSubject.asObservable() - } - }, - provideMockFeatureFlags({ ['studio-ws-graphql-subprotocol']: true }) - ] - }); - service = TestBed.inject(WebSocketService); - featureService = TestBed.inject(FeaturesServiceToken); - spyOn(featureService, 'isOn$').and.returnValue(of(true)); - apolloMock.use.and.returnValues(undefined, { subscribe: () => of({}) }); - }); - - afterEach(() => { - apolloMock.use.calls.reset(); - apolloMock.createNamed.calls.reset(); - }); - - it('should not create a new Apollo client if it is already in use', (done) => { - const apolloClientName = 'testClient'; - const subscriptionOptions: SubscriptionOptions = { query: gql(`subscription {testQuery}`) }; - const wsOptions = { apolloClientName, wsUrl: 'testUrl', subscriptionOptions }; - - apolloMock.use.and.returnValues(true, { subscribe: () => of({}) }); - - service.getSubscription(wsOptions).subscribe(() => { - expect(apolloMock.use).toHaveBeenCalledTimes(2); - expect(apolloMock.use).toHaveBeenCalledWith(apolloClientName); - expect(apolloMock.createNamed).not.toHaveBeenCalled(); - done(); - }); - }); - - it('should subscribe to Apollo client if not already in use', (done) => { - const apolloClientName = 'testClient'; - const expectedApolloClientName = 'testClient'; - const subscriptionOptions: SubscriptionOptions = { query: gql(`subscription {testQuery}`) }; - const wsOptions = { apolloClientName, wsUrl: 'testUrl', subscriptionOptions }; - - service.getSubscription(wsOptions).subscribe(() => { - expect(apolloMock.use).toHaveBeenCalledWith(expectedApolloClientName); - expect(apolloMock.use).toHaveBeenCalledTimes(2); - expect(apolloMock.createNamed).toHaveBeenCalledTimes(1); - expect(apolloMock.createNamed).toHaveBeenCalledWith(expectedApolloClientName, jasmine.any(Object)); - done(); - }); - }); - - it('should create named client with the right authentication token when FF is on', (done) => { - let headers = {}; - const expectedHeaders = { Authorization: 'Bearer testToken' }; - const apolloClientName = 'testClient'; - const subscriptionOptions: SubscriptionOptions = { query: gql(`subscription {testQuery}`) }; - const wsOptions = { apolloClientName, wsUrl: 'testUrl', subscriptionOptions }; - apolloMock.createNamed.and.callFake((_, options) => { - headers = options.headers; - }); - - service.getSubscription(wsOptions).subscribe(() => { - expect(apolloMock.use).toHaveBeenCalledTimes(2); - expect(apolloMock.createNamed).toHaveBeenCalled(); - expect(headers).toEqual(expectedHeaders); - done(); - }); - }); - - it('should create named client with the right authentication token when FF is off', (done) => { - featureService.isOn$ = jasmine.createSpy().and.returnValue(of(false)); - let headers = {}; - const expectedHeaders = { 'X-Authorization': 'Bearer testToken' }; - const apolloClientName = 'testClient'; - const subscriptionOptions: SubscriptionOptions = { query: gql(`subscription {testQuery}`) }; - const wsOptions = { apolloClientName, wsUrl: 'testUrl', subscriptionOptions }; - apolloMock.createNamed.and.callFake((_, options) => { - headers = options.headers; - }); - - service.getSubscription(wsOptions).subscribe(() => { - expect(apolloMock.use).toHaveBeenCalledTimes(2); - expect(apolloMock.createNamed).toHaveBeenCalled(); - expect(headers).toEqual(expectedHeaders); - done(); - }); - }); -}); diff --git a/lib/process-services-cloud/src/lib/services/web-socket.service.ts b/lib/process-services-cloud/src/lib/services/web-socket.service.ts deleted file mode 100644 index 0b10f54925..0000000000 --- a/lib/process-services-cloud/src/lib/services/web-socket.service.ts +++ /dev/null @@ -1,211 +0,0 @@ -/*! - * @license - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { createClient } from 'graphql-ws'; -import { Inject, Injectable } from '@angular/core'; -import { AppConfigService, AuthenticationService } from '@alfresco/adf-core'; -import { GraphQLWsLink } from '@apollo/client/link/subscriptions'; -import { WebSocketLink } from '@apollo/client/link/ws'; -import { - DefaultContext, - FetchResult, - from, - HttpLink, - InMemoryCache, - InMemoryCacheConfig, - NextLink, - Operation, - split, - SubscriptionOptions -} from '@apollo/client/core'; -import { getMainDefinition } from '@apollo/client/utilities'; -import { Kind, OperationTypeNode } from 'graphql'; -import { Apollo } from 'apollo-angular'; -import { onError } from '@apollo/client/link/error'; -import { RetryLink } from '@apollo/client/link/retry'; -import { Observable } from 'rxjs'; -import { switchMap, take, tap } from 'rxjs/operators'; -import { FeaturesServiceToken, IFeaturesService } from '@alfresco/adf-core/feature-flags'; - -interface serviceOptions { - apolloClientName: string; - wsUrl: string; - httpUrl?: string; - subscriptionOptions: SubscriptionOptions; -} - -@Injectable({ - providedIn: 'root' -}) -export class WebSocketService { - private host = ''; - private subscriptionProtocol: 'graphql-ws' | 'transport-ws' = 'transport-ws'; - private wsLink: GraphQLWsLink | WebSocketLink; - private httpLink: HttpLink; - - constructor( - private readonly apollo: Apollo, - private readonly appConfigService: AppConfigService, - private readonly authService: AuthenticationService, - @Inject(FeaturesServiceToken) private featuresService: IFeaturesService - ) { - this.host = this.appConfigService.get('bpmHost', ''); - } - - public getSubscription(options: serviceOptions): Observable> { - const { apolloClientName, subscriptionOptions } = options; - this.authService.onLogout.pipe(take(1)).subscribe(() => { - if (this.apollo.use(apolloClientName)) { - this.apollo.removeClient(apolloClientName); - } - }); - - return this.featuresService.isOn$('studio-ws-graphql-subprotocol').pipe( - tap((isOn) => { - if (isOn) { - this.subscriptionProtocol = 'graphql-ws'; - } - }), - switchMap(() => { - if (this.apollo.use(apolloClientName) === undefined) { - this.initSubscriptions(options); - } - return this.apollo.use(apolloClientName).subscribe({ errorPolicy: 'all', ...subscriptionOptions }); - }) - ); - } - - private createWsUrl(serviceUrl: string): string { - const url = new URL(serviceUrl, this.host); - const protocol = url.protocol === 'https:' ? 'wss:' : 'ws:'; - url.protocol = protocol; - - return url.href; - } - - private createHttpUrl(serviceUrl: string): string { - const url = new URL(serviceUrl, this.host); - - return url.href; - } - - private initSubscriptions(options: serviceOptions): void { - switch (this.subscriptionProtocol) { - case 'graphql-ws': - this.createGraphQLWsLink(options); - break; - case 'transport-ws': - this.createTransportWsLink(options); - break; - default: - throw new Error('Unknown subscription protocol'); - } - - this.httpLink = options.httpUrl - ? new HttpLink({ - uri: this.createHttpUrl(options.httpUrl) - }) - : undefined; - - const link = split( - ({ query }) => { - const definition = getMainDefinition(query); - return definition.kind === Kind.OPERATION_DEFINITION && definition.operation === OperationTypeNode.SUBSCRIPTION; - }, - this.wsLink, - this.httpLink - ); - - const authLink = (operation: Operation, forward: NextLink) => { - operation.setContext(({ headers }: DefaultContext) => ({ - headers: { - ...headers, - ...(this.subscriptionProtocol === 'graphql-ws' && { Authorization: `Bearer ${this.authService.getToken()}` }), - ...(this.subscriptionProtocol === 'transport-ws' && { 'X-Authorization': `Bearer ${this.authService.getToken()}` }) - } - })); - return forward(operation); - }; - - const errorLink = onError(({ graphQLErrors, networkError, operation, forward }) => { - if (graphQLErrors) { - for (const error of graphQLErrors) { - if (error.extensions && error.extensions['code'] === 'UNAUTHENTICATED') { - authLink(operation, forward); - } - } - } - - if (networkError) { - console.error(`[Network error]: ${networkError}`); - } - }); - - const retryLink = new RetryLink({ - delay: { - initial: 300, - max: Number.POSITIVE_INFINITY, - jitter: true - }, - attempts: { - max: 5, - retryIf: (error) => !!error - } - }); - - this.apollo.createNamed(options.apolloClientName, { - headers: { - ...(this.subscriptionProtocol === 'graphql-ws' && { Authorization: `Bearer ${this.authService.getToken()}` }), - ...(this.subscriptionProtocol === 'transport-ws' && { 'X-Authorization': `Bearer ${this.authService.getToken()}` }) - }, - link: from([authLink, retryLink, errorLink, link]), - cache: new InMemoryCache({ merge: true } as InMemoryCacheConfig) - }); - } - - private createTransportWsLink(options: serviceOptions) { - this.wsLink = new WebSocketLink({ - uri: this.createWsUrl(options.wsUrl) + '/ws/graphql', - options: { - reconnect: true, - lazy: true, - connectionParams: { - kaInterval: 2000, - 'X-Authorization': 'Bearer ' + this.authService.getToken() - } - } - }); - } - - private createGraphQLWsLink(options: serviceOptions) { - this.wsLink = new GraphQLWsLink( - createClient({ - url: this.createWsUrl(options.wsUrl) + '/v2/ws/graphql', - connectionParams: { - Authorization: 'Bearer ' + this.authService.getToken() - }, - on: { - error: () => { - this.apollo.removeClient(options.apolloClientName); - this.initSubscriptions(options); - } - }, - lazy: true - }) - ); - } -} diff --git a/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/edit-service-task-filter-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/edit-service-task-filter-cloud.component.spec.ts index b97686b4ee..9905455fc9 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/edit-service-task-filter-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/edit-service-task-filter-cloud.component.spec.ts @@ -39,7 +39,6 @@ import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { MatExpansionPanelHarness } from '@angular/material/expansion/testing'; import { MatSelectHarness } from '@angular/material/select/testing'; import { MatProgressSpinnerHarness } from '@angular/material/progress-spinner/testing'; -import { provideMockFeatureFlags } from '@alfresco/adf-core/feature-flags'; describe('EditServiceTaskFilterCloudComponent', () => { let loader: HarnessLoader; @@ -51,16 +50,12 @@ describe('EditServiceTaskFilterCloudComponent', () => { let getTaskFilterSpy: jasmine.Spy; let getDeployedApplicationsSpy: jasmine.Spy; let taskService: TaskCloudService; - const afterClosedSubject = new Subject(); + const afterClosedSubject = new Subject(); beforeEach(() => { TestBed.configureTestingModule({ imports: [ProcessServiceCloudTestingModule, TaskFiltersCloudModule, MatIconTestingModule], - providers: [ - MatDialog, - { provide: TASK_FILTERS_SERVICE_TOKEN, useClass: LocalPreferenceCloudService }, - provideMockFeatureFlags({ ['studio-ws-graphql-subprotocol']: false }) - ] + providers: [MatDialog, { provide: TASK_FILTERS_SERVICE_TOKEN, useClass: LocalPreferenceCloudService }] }); fixture = TestBed.createComponent(EditServiceTaskFilterCloudComponent); component = fixture.componentInstance; @@ -68,8 +63,9 @@ describe('EditServiceTaskFilterCloudComponent', () => { appsService = TestBed.inject(AppsProcessCloudService); taskService = TestBed.inject(TaskCloudService); dialog = TestBed.inject(MatDialog); - const dialogRefMock = jasmine.createSpyObj('MatDialogRef', ['afterClosed']); - dialogRefMock.afterClosed.and.returnValue(afterClosedSubject); + const dialogRefMock: any = { + afterClosed: () => afterClosedSubject + }; spyOn(dialog, 'open').and.returnValue(dialogRefMock); getTaskFilterSpy = spyOn(service, 'getTaskFilterById').and.returnValue(of(fakeServiceFilter)); getDeployedApplicationsSpy = spyOn(appsService, 'getDeployedApplicationsByStatus').and.returnValue(of(fakeApplicationInstance)); diff --git a/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/edit-task-filter-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/edit-task-filter-cloud.component.spec.ts index a5093faa82..8e0481f505 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/edit-task-filter-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/task/task-filters/components/edit-task-filters/edit-task-filter-cloud.component.spec.ts @@ -57,7 +57,6 @@ import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { MatSelectHarness } from '@angular/material/select/testing'; import { MatExpansionPanelHarness } from '@angular/material/expansion/testing'; import { MatProgressSpinnerHarness } from '@angular/material/progress-spinner/testing'; -import { provideMockFeatureFlags } from '@alfresco/adf-core/feature-flags'; describe('EditTaskFilterCloudComponent', () => { let loader: HarnessLoader; @@ -71,16 +70,12 @@ describe('EditTaskFilterCloudComponent', () => { let getTaskFilterSpy: jasmine.Spy; let getDeployedApplicationsSpy: jasmine.Spy; let taskService: TaskCloudService; - const afterClosedSubject = new Subject(); + const afterClosedSubject = new Subject(); beforeEach(() => { TestBed.configureTestingModule({ imports: [ProcessServiceCloudTestingModule, TaskFiltersCloudModule, PeopleCloudModule, MatIconTestingModule], - providers: [ - MatDialog, - { provide: TASK_FILTERS_SERVICE_TOKEN, useClass: LocalPreferenceCloudService }, - provideMockFeatureFlags({ ['studio-ws-graphql-subprotocol']: false }) - ] + providers: [MatDialog, { provide: TASK_FILTERS_SERVICE_TOKEN, useClass: LocalPreferenceCloudService }] }); fixture = TestBed.createComponent(EditTaskFilterCloudComponent); component = fixture.componentInstance; @@ -90,8 +85,9 @@ describe('EditTaskFilterCloudComponent', () => { taskService = TestBed.inject(TaskCloudService); alfrescoApiService = TestBed.inject(AlfrescoApiService); dialog = TestBed.inject(MatDialog); - const dialogRefMock = jasmine.createSpyObj('MatDialogRef', ['afterClosed']); - dialogRefMock.afterClosed.and.returnValue(afterClosedSubject); + const dialogRefMock: any = { + afterClosed: () => afterClosedSubject + }; spyOn(dialog, 'open').and.returnValue(dialogRefMock); spyOn(alfrescoApiService, 'getInstance').and.returnValue(mockAlfrescoApi); getTaskFilterSpy = spyOn(service, 'getTaskFilterById').and.returnValue(of(fakeFilter)); diff --git a/lib/process-services-cloud/src/lib/task/task-filters/components/task-filters-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/task/task-filters/components/task-filters-cloud.component.spec.ts index 37973cdaf7..9a158551f7 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/components/task-filters-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/task/task-filters/components/task-filters-cloud.component.spec.ts @@ -16,7 +16,7 @@ */ import { AppConfigService } from '@alfresco/adf-core'; -import { DebugElement, SimpleChange } from '@angular/core'; +import { SimpleChange } from '@angular/core'; import { ComponentFixture, TestBed, fakeAsync } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { first, of, throwError } from 'rxjs'; @@ -32,7 +32,6 @@ import { HarnessLoader } from '@angular/cdk/testing'; import { MatActionListItemHarness } from '@angular/material/list/testing'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { TaskFilterCloudAdapter } from '../../../models/filter-cloud-model'; -import { provideMockFeatureFlags } from '@alfresco/adf-core/feature-flags'; describe('TaskFiltersCloudComponent', () => { let loader: HarnessLoader; @@ -46,14 +45,10 @@ describe('TaskFiltersCloudComponent', () => { let getTaskListFiltersSpy: jasmine.Spy; let getTaskListCounterSpy: jasmine.Spy; - const configureTestingModule = (providers: unknown[]) => { + const configureTestingModule = (providers: any[]) => { TestBed.configureTestingModule({ imports: [ProcessServiceCloudTestingModule, TaskFiltersCloudModule], - providers: [ - { provide: TASK_FILTERS_SERVICE_TOKEN, useClass: LocalPreferenceCloudService }, - provideMockFeatureFlags({ ['studio-ws-graphql-subprotocol']: false }), - ...providers - ] + providers: [{ provide: TASK_FILTERS_SERVICE_TOKEN, useClass: LocalPreferenceCloudService }, ...providers] }); taskFilterService = TestBed.inject(TaskFilterCloudService); taskListService = TestBed.inject(TaskListCloudService); @@ -107,7 +102,7 @@ describe('TaskFiltersCloudComponent', () => { fixture.detectChanges(); await fixture.whenStable(); - const filters: DebugElement[] = fixture.debugElement.queryAll(By.css('.adf-icon')); + const filters: any = fixture.debugElement.queryAll(By.css('.adf-icon')); expect(filters.length).toBe(0); }); @@ -270,7 +265,7 @@ describe('TaskFiltersCloudComponent', () => { component.showIcons = false; fixture.detectChanges(); - const filters: DebugElement[] = fixture.debugElement.queryAll(By.css('.adf-icon')); + const filters: any = fixture.debugElement.queryAll(By.css('.adf-icon')); expect(filters.length).toBe(0); }); diff --git a/lib/process-services-cloud/src/lib/task/task-filters/services/task-filter-cloud.service.spec.ts b/lib/process-services-cloud/src/lib/task/task-filters/services/task-filter-cloud.service.spec.ts index e69dc1764d..09e48f0e08 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/services/task-filter-cloud.service.spec.ts +++ b/lib/process-services-cloud/src/lib/task/task-filters/services/task-filter-cloud.service.spec.ts @@ -37,7 +37,6 @@ import { IdentityUserService } from '../../../people/services/identity-user.serv import { ApolloModule } from 'apollo-angular'; import { StorageService } from '@alfresco/adf-core'; import { TaskStatusFilter } from '../public-api'; -import { provideMockFeatureFlags } from '@alfresco/adf-core/feature-flags'; describe('TaskFilterCloudService', () => { let service: TaskFilterCloudService; @@ -58,10 +57,7 @@ describe('TaskFilterCloudService', () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule, ProcessServiceCloudTestingModule, ApolloModule], - providers: [ - { provide: TASK_FILTERS_SERVICE_TOKEN, useClass: UserPreferenceCloudService }, - provideMockFeatureFlags({ ['studio-ws-graphql-subprotocol']: false }) - ] + providers: [{ provide: TASK_FILTERS_SERVICE_TOKEN, useClass: UserPreferenceCloudService }] }); service = TestBed.inject(TaskFilterCloudService); notificationCloudService = TestBed.inject(NotificationCloudService); @@ -270,10 +266,7 @@ describe('Inject [LocalPreferenceCloudService] into the TaskFilterCloudService', beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule, ProcessServiceCloudTestingModule, ApolloModule], - providers: [ - { provide: TASK_FILTERS_SERVICE_TOKEN, useClass: LocalPreferenceCloudService }, - provideMockFeatureFlags({ ['studio-ws-graphql-subprotocol']: false }) - ] + providers: [{ provide: TASK_FILTERS_SERVICE_TOKEN, useClass: LocalPreferenceCloudService }] }); service = TestBed.inject(TaskFilterCloudService); preferenceCloudService = service.preferenceService; diff --git a/package-lock.json b/package-lock.json index 55bb455463..8a7a941e79 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,7 +35,6 @@ "date-fns": "^2.30.0", "dotenv-expand": "^5.1.0", "event-emitter": "^0.3.5", - "graphql-ws": "^5.16.0", "material-icons": "^1.13.12", "minimatch-browser": "1.0.0", "ng2-charts": "^4.1.1", @@ -116,7 +115,7 @@ "eslint-plugin-rxjs": "^5.0.3", "eslint-plugin-storybook": "^0.11.1", "eslint-plugin-unicorn": "^49.0.0", - "graphql": "^16.9.0", + "graphql": "^16.8.1", "husky": "^7.0.4", "jasmine-ajax": "4.0.0", "jasmine-core": "5.4.0", @@ -19157,8 +19156,7 @@ }, "node_modules/graphql": { "version": "16.9.0", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz", - "integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==", + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } @@ -19176,20 +19174,6 @@ "graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, - "node_modules/graphql-ws": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.16.0.tgz", - "integrity": "sha512-Ju2RCU2dQMgSKtArPbEtsK5gNLnsQyTNIo/T7cZNp96niC1x0KdJNZV0TIoilceBPQwfb5itrGl8pkFeOUMl4A==", - "workspaces": [ - "website" - ], - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "graphql": ">=0.11 <=16" - } - }, "node_modules/guess-parser": { "version": "0.4.22", "dev": true, diff --git a/package.json b/package.json index 173d958618..c69ccf8a9c 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,6 @@ "date-fns": "^2.30.0", "dotenv-expand": "^5.1.0", "event-emitter": "^0.3.5", - "graphql-ws": "^5.16.0", "material-icons": "^1.13.12", "minimatch-browser": "1.0.0", "ng2-charts": "^4.1.1", @@ -136,7 +135,7 @@ "eslint-plugin-rxjs": "^5.0.3", "eslint-plugin-storybook": "^0.11.1", "eslint-plugin-unicorn": "^49.0.0", - "graphql": "^16.9.0", + "graphql": "^16.8.1", "husky": "^7.0.4", "jasmine-ajax": "4.0.0", "jasmine-core": "5.4.0",