From 4a80a90451ea09a799a4b810bd5dd33d20dd6b7e Mon Sep 17 00:00:00 2001 From: VitoAlbano Date: Wed, 10 Sep 2025 00:46:41 +0100 Subject: [PATCH] AAE-30882 - Start fixing some unit tests - check 1 --- ...lytics-report-parameters.component.spec.ts | 19 +- lib/js-api/test/alfrescoApi.spec.ts | 18 +- lib/js-api/test/ecmAuth.spec.ts | 1 + .../security-groups.mock.ts | 2 - lib/js-api/test/oauth2Auth.spec.ts | 227 ++++++++++++------ 5 files changed, 175 insertions(+), 92 deletions(-) diff --git a/lib/insights/src/lib/analytics-process/components/analytics-report-parameters.component.spec.ts b/lib/insights/src/lib/analytics-process/components/analytics-report-parameters.component.spec.ts index 0cefa1c58e..b86805f71b 100644 --- a/lib/insights/src/lib/analytics-process/components/analytics-report-parameters.component.spec.ts +++ b/lib/insights/src/lib/analytics-process/components/analytics-report-parameters.component.spec.ts @@ -395,24 +395,37 @@ describe('AnalyticsReportParametersComponent', () => { beforeEach(async () => { const reportId = 1; const change = new SimpleChange(null, reportId, true); - component.ngOnChanges({ reportId: change }); - fixture.detectChanges(); - jasmine.Ajax.requests.mostRecent().respondWith({ + // Set up the mock response before triggering the change + jasmine.Ajax.stubRequest('http://localhost:9876/bpm/activiti-app/app/rest/reporting/report-params/1').andReturn({ status: 200, contentType: 'json', responseText: analyticParamsMock.reportDefParamStatus }); + component.ngOnChanges({ reportId: change }); + fixture.detectChanges(); await fixture.whenStable(); + + // Ensure the component has processed the report parameters component.toggleParameters(); fixture.detectChanges(); + await fixture.whenStable(); }); it('Should be able to change the report title', async () => { spyOn(service, 'updateReport').and.returnValue(of(analyticParamsMock.reportDefParamStatus)); + // Trigger change detection like the other working tests do + fixture.detectChanges(); + await fixture.whenStable(); + + // Wait for the component to be properly initialized from the beforeEach + expect(component.reportParameters).toBeDefined(); + expect(component.reportParameters.name).toBe('Fake Task overview status'); + const title = element.querySelector('h4'); + expect(title).not.toBeNull(); title.click(); fixture.detectChanges(); diff --git a/lib/js-api/test/alfrescoApi.spec.ts b/lib/js-api/test/alfrescoApi.spec.ts index 2df2549d54..62f7241b08 100644 --- a/lib/js-api/test/alfrescoApi.spec.ts +++ b/lib/js-api/test/alfrescoApi.spec.ts @@ -216,7 +216,7 @@ describe('Basic configuration test', () => { it('Should login be rejected if username or password are not provided', async () => { const hostEcm = 'https://testServer.com:1616'; - const authEcmMock = new EcmAuthMock(hostEcm); // ✅ HAS MOCK + const authEcmMock = new EcmAuthMock(hostEcm); const config = { hostEcm, @@ -236,7 +236,7 @@ describe('Basic configuration test', () => { assert.equal(error, 'missing username or password'); error = undefined; - + authEcmMock.get401InvalidRequest(); try { await alfrescoJsApi.login('username', undefined); } catch (e) { @@ -246,7 +246,7 @@ describe('Basic configuration test', () => { assert.equal(error, 'missing username or password'); error = undefined; - + authEcmMock.get401InvalidRequest(); try { await alfrescoJsApi.login(undefined, 'password'); } catch (e) { @@ -256,7 +256,7 @@ describe('Basic configuration test', () => { assert.equal(error, 'missing username or password'); error = undefined; - + authEcmMock.get401InvalidRequest(); try { await alfrescoJsApi.login('', ''); } catch (e) { @@ -266,7 +266,7 @@ describe('Basic configuration test', () => { assert.equal(error, 'missing username or password'); error = undefined; - + authEcmMock.get401InvalidRequest(); try { await alfrescoJsApi.login('username', ''); } catch (e) { @@ -276,7 +276,7 @@ describe('Basic configuration test', () => { assert.equal(error, 'missing username or password'); error = undefined; - + authEcmMock.get401InvalidRequest(); try { await alfrescoJsApi.login('', 'password'); } catch (e) { @@ -325,11 +325,15 @@ describe('Basic configuration test', () => { }); it('Should logged-in be emitted when log in OAUTH', (done) => { - const oauth2Mock = new OAuthMock('https://myOauthUrl:30081'); + const host = 'https://myOauthUrl:30081'; + const oauth2Mock = new OAuthMock(host); + const authEcmMock = new EcmAuthMock(host); oauth2Mock.get200Response(); + authEcmMock.get200ValidTicket(); const alfrescoJsApi = new AlfrescoApi({ + hostEcm: host, oauth2: { host: 'https://myOauthUrl:30081/auth/realms/springboot', clientId: 'activiti', diff --git a/lib/js-api/test/ecmAuth.spec.ts b/lib/js-api/test/ecmAuth.spec.ts index 7d51635afd..e4ebf5dec3 100644 --- a/lib/js-api/test/ecmAuth.spec.ts +++ b/lib/js-api/test/ecmAuth.spec.ts @@ -44,6 +44,7 @@ describe('Ecm Auth test', () => { it('should remember username on login', () => { const auth = new ContentAuth({}, alfrescoJsApi); + authEcmMock.get201ResponseJohnDoe(); auth.login('johndoe', 'password'); assert.equal(auth.authentications.basicAuth.username, 'johndoe'); }); diff --git a/lib/js-api/test/mockObjects/goverance-services/security-groups.mock.ts b/lib/js-api/test/mockObjects/goverance-services/security-groups.mock.ts index 58771183a4..d73aa0f5e6 100644 --- a/lib/js-api/test/mockObjects/goverance-services/security-groups.mock.ts +++ b/lib/js-api/test/mockObjects/goverance-services/security-groups.mock.ts @@ -15,9 +15,7 @@ * limitations under the License. */ -import { th } from 'date-fns/locale'; import { BaseMock } from '../base.mock'; -import nock from 'nock'; export class SecurityGroupApiMock extends BaseMock { createSecurityGroup200Response(): void { diff --git a/lib/js-api/test/oauth2Auth.spec.ts b/lib/js-api/test/oauth2Auth.spec.ts index 316bc73337..ee53d13fe9 100644 --- a/lib/js-api/test/oauth2Auth.spec.ts +++ b/lib/js-api/test/oauth2Auth.spec.ts @@ -19,6 +19,45 @@ import assert from 'assert'; import { AlfrescoApi, ContentApi, Oauth2Auth } from '../src'; import { EcmAuthMock, OAuthMock } from './mockObjects'; import { jest } from '@jest/globals'; +import nock from 'nock'; + +const setupTestEnvironment = () => { + const originalDocument = global.document; + const originalSetInterval = global.setInterval; + const mockIntervals: { id: NodeJS.Timeout; unref: jest.Mock }[] = []; + + delete (global as unknown as { document?: Document }).document; + + global.setInterval = jest.fn((callback: () => void, delay: number) => { + const intervalId = originalSetInterval(callback, delay); + const mockInterval = { + id: intervalId, + unref: jest.fn(() => mockInterval) + }; + mockIntervals.push(mockInterval); + return mockInterval; + }); + + return { originalDocument, originalSetInterval, mockIntervals }; +}; + +const restoreTestEnvironment = (context: { + originalDocument: Document; + originalSetInterval: typeof setInterval; + mockIntervals: { id: NodeJS.Timeout; unref: jest.Mock }[]; +}) => { + context.mockIntervals.forEach((interval) => { + if (interval.id) { + clearInterval(interval.id); + } + }); + + global.setInterval = context.originalSetInterval; + + if (context.originalDocument) { + global.document = context.originalDocument; + } +}; describe('Oauth2 test', () => { let alfrescoJsApi: AlfrescoApi; @@ -191,75 +230,88 @@ describe('Oauth2 test', () => { }); }); - it('should refresh token when the login not use the implicitFlow ', (done) => { - jest.spyOn(window, 'document', 'get').mockReturnValueOnce(undefined); - oauth2Mock.get200Response(); + it('should refresh token when the login not use the implicitFlow', async () => { + const testContext = setupTestEnvironment(); - const oauth2Auth = new Oauth2Auth( - { - oauth2: { - host: 'https://myOauthUrl:30081/auth/realms/springboot', - clientId: 'activiti', - scope: 'openid', - secret: '', - redirectUri: '/', - redirectUriLogout: '/logout', - implicitFlow: false, - refreshTokenTimeout: 100 + try { + oauth2Mock.get200Response(); + + const oauth2Auth = new Oauth2Auth( + { + oauth2: { + host: 'https://myOauthUrl:30081/auth/realms/springboot', + clientId: 'activiti', + scope: 'openid', + secret: '', + redirectUri: '/', + redirectUriLogout: '/logout', + implicitFlow: false, + refreshTokenTimeout: 100 + }, + authType: 'OAUTH' }, - authType: 'OAUTH' - }, - alfrescoJsApi - ); + alfrescoJsApi + ); - let calls = 0; - oauth2Auth.refreshToken = () => { - calls++; - return Promise.resolve(); - }; + let refreshTokenCallCount = 0; - setTimeout(() => { - assert.equal(calls > 2, true); - oauth2Auth.logOut(); - done(); - }, 600); + jest.spyOn(oauth2Auth, 'refreshToken').mockImplementation(() => { + refreshTokenCallCount++; + return Promise.resolve(); + }); - oauth2Auth.login('admin', 'admin'); + await oauth2Auth.login('admin', 'admin'); + await new Promise((resolve) => setTimeout(resolve, 250)); + + expect(refreshTokenCallCount).toBeGreaterThanOrEqual(2); + expect(testContext.mockIntervals.length).toBe(1); + expect(testContext.mockIntervals[0].unref).toHaveBeenCalled(); + + await oauth2Auth.logOut(); + } finally { + restoreTestEnvironment(testContext); + } }); - it('should not hang the app also if the logout is missing', (done) => { - jest.spyOn(window, 'document', 'get').mockReturnValueOnce(undefined); - oauth2Mock.get200Response(); + it('should not hang the app also if the logout is missing', async () => { + const testContext = setupTestEnvironment(); - const oauth2Auth = new Oauth2Auth( - { - oauth2: { - host: 'https://myOauthUrl:30081/auth/realms/springboot', - clientId: 'activiti', - scope: 'openid', - secret: '', - redirectUri: '/', - redirectUriLogout: '/logout', - implicitFlow: false, - refreshTokenTimeout: 100 + try { + oauth2Mock.get200Response(); + + const oauth2Auth = new Oauth2Auth( + { + oauth2: { + host: 'https://myOauthUrl:30081/auth/realms/springboot', + clientId: 'activiti', + scope: 'openid', + secret: '', + redirectUri: '/', + redirectUriLogout: '/logout', + implicitFlow: false, + refreshTokenTimeout: 100 + }, + authType: 'OAUTH' }, - authType: 'OAUTH' - }, - alfrescoJsApi - ); + alfrescoJsApi + ); - let calls = 0; - oauth2Auth.refreshToken = () => { - calls++; - return Promise.resolve(); - }; + let refreshTokenCallCount = 0; - setTimeout(() => { - assert.equal(calls > 2, true); - done(); - }, 600); + jest.spyOn(oauth2Auth, 'refreshToken').mockImplementation(() => { + refreshTokenCallCount++; + return Promise.resolve(); + }); - oauth2Auth.login('admin', 'admin'); + await oauth2Auth.login('admin', 'admin'); + await new Promise((resolve) => setTimeout(resolve, 250)); + + expect(refreshTokenCallCount).toBeGreaterThanOrEqual(2); + expect(testContext.mockIntervals.length).toBe(1); + expect(testContext.mockIntervals[0].unref).toHaveBeenCalled(); + } finally { + restoreTestEnvironment(testContext); + } }); it('should emit a token_issued event if login is ok ', (done) => { @@ -353,6 +405,7 @@ describe('Oauth2 test', () => { authResponseMock.get200ValidTicket(); const oauth2Auth = new Oauth2Auth( { + hostEcm: 'https://myOauthUrl:30081', provider: 'ALL', oauth2: { host: 'https://myOauthUrl:30081/auth/realms/springboot', @@ -446,13 +499,10 @@ describe('Oauth2 test', () => { alfrescoApi.login('admin', 'admin'); }); - // TODO: very flaky test, fails on different machines if running slow, might relate to `this.timeout` - // eslint-disable-next-line ban/ban - xit('should extend content session after oauth token refresh', function (done) { - jest.setTimeout(3000); - + it('should extend content session after oauth token refresh', async () => { oauth2Mock.get200Response(); authResponseMock.get200ValidTicket(); + authResponseMock.get200ValidTicket(); const alfrescoApi = new AlfrescoApi({ hostEcm: 'https://myOauthUrl:30081', @@ -467,28 +517,46 @@ describe('Oauth2 test', () => { authType: 'OAUTH' }); - let counterCallEvent = 0; - alfrescoApi.oauth2Auth.on('ticket_exchanged', () => { - assert.equal(alfrescoApi.config.ticketEcm, 'TICKET_4479f4d3bb155195879bfbb8d5206f433488a1b1'); - assert.equal(alfrescoApi.contentClient.config.ticketEcm, 'TICKET_4479f4d3bb155195879bfbb8d5206f433488a1b1'); + let ticketExchangeCount = 0; - const content = new ContentApi(alfrescoApi); - const URL = content.getContentUrl('FAKE-NODE-ID'); - assert.equal( - URL, - 'https://myOauthUrl:30081/alfresco/api/-default-/public/alfresco/versions/1/nodes/FAKE-NODE-ID/content?attachment=false&alf_ticket=TICKET_4479f4d3bb155195879bfbb8d5206f433488a1b1' - ); + const ticketExchangePromise = new Promise((resolve) => { + alfrescoApi.oauth2Auth.on('ticket_exchanged', () => { + expect(alfrescoApi.config.ticketEcm).toBe('TICKET_4479f4d3bb155195879bfbb8d5206f433488a1b1'); + expect(alfrescoApi.contentClient.config.ticketEcm).toBe('TICKET_4479f4d3bb155195879bfbb8d5206f433488a1b1'); - counterCallEvent++; + const content = new ContentApi(alfrescoApi); + const URL = content.getContentUrl('FAKE-NODE-ID'); + expect(URL).toBe( + 'https://myOauthUrl:30081/alfresco/api/-default-/public/alfresco/versions/1/nodes/FAKE-NODE-ID/content?attachment=false&alf_ticket=TICKET_4479f4d3bb155195879bfbb8d5206f433488a1b1' + ); - if (counterCallEvent === 2) { - done(); - } + ticketExchangeCount++; + + if (ticketExchangeCount === 2) { + resolve(); + } + }); }); - alfrescoApi.login('admin', 'admin'); - jest.setTimeout(3000); - alfrescoApi.refreshToken(); + jest.spyOn(alfrescoApi.oauth2Auth, 'refreshToken').mockImplementation(() => { + alfrescoApi.oauth2Auth.setToken('refreshed-test-token', 'new-refresh-token'); + return Promise.resolve({ + access_token: 'refreshed-test-token', + refresh_token: 'new-refresh-token' + }); + }); + + await alfrescoApi.login('admin', 'admin'); + + await new Promise((resolve) => setTimeout(resolve, 100)); + + await alfrescoApi.oauth2Auth.refreshToken(); + + await ticketExchangePromise; + + expect(ticketExchangeCount).toBe(2); + + await alfrescoApi.oauth2Auth.logOut(); }); it('isLoggedIn should return true if the api is logged in', (done) => { @@ -569,7 +637,6 @@ describe('Oauth2 test', () => { return Promise.resolve(); }; - // invalid hash location leads to a reject which leads to a logout oauth2Auth.iFrameHashListener(); assert.equal(logoutCalled, true); done();