* #708 apply strictier linting rules and fix simple eslint bugs * #708 fix eslint errors relate to promise * #708 fix eslint import/no-extraneous-dependencies * #708 fix eslint errors of react-hook * #708 enable eslint check for typescript --------- Co-authored-by: lethemanh <lethemanh@lethemanhs-MacBook-Pro.local>
This commit is contained in:
@@ -1,45 +1,45 @@
|
||||
import * as appHooks from "@/app/hooks";
|
||||
import { AppDispatch, setupStore } from "@/app/store";
|
||||
import HandleLogin from "@/features/User/HandleLogin";
|
||||
import * as oidcAuth from "@/features/User/oidcAuth";
|
||||
import { clientConfig } from "@/features/User/oidcAuth";
|
||||
import { useInitializeApp } from "@/features/User/useInitializeApp";
|
||||
import * as apiUtils from "@/utils/apiUtils";
|
||||
import { renderHook, screen, waitFor } from "@testing-library/react";
|
||||
import { Provider } from "react-redux";
|
||||
import { push } from "redux-first-history";
|
||||
import { renderWithProviders } from "../../utils/Renderwithproviders";
|
||||
import * as appHooks from '@/app/hooks'
|
||||
import { AppDispatch, setupStore } from '@/app/store'
|
||||
import HandleLogin from '@/features/User/HandleLogin'
|
||||
import * as oidcAuth from '@/features/User/oidcAuth'
|
||||
import { clientConfig } from '@/features/User/oidcAuth'
|
||||
import { useInitializeApp } from '@/features/User/useInitializeApp'
|
||||
import * as apiUtils from '@/utils/apiUtils'
|
||||
import { renderHook, screen, waitFor } from '@testing-library/react'
|
||||
import { Provider } from 'react-redux'
|
||||
import { push } from 'redux-first-history'
|
||||
import { renderWithProviders } from '../../utils/Renderwithproviders'
|
||||
|
||||
clientConfig.url = "https://example.com";
|
||||
clientConfig.url = 'https://example.com'
|
||||
|
||||
describe("HandleLogin", () => {
|
||||
describe('HandleLogin', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
jest.spyOn(apiUtils, "redirectTo").mockImplementation(() => {});
|
||||
const dispatch = jest.fn() as AppDispatch;
|
||||
jest.spyOn(appHooks, "useAppDispatch").mockReturnValue(dispatch);
|
||||
sessionStorage.clear();
|
||||
Object.defineProperty(window, "matchMedia", {
|
||||
jest.clearAllMocks()
|
||||
jest.spyOn(apiUtils, 'redirectTo').mockImplementation(() => {})
|
||||
const dispatch = jest.fn() as AppDispatch
|
||||
jest.spyOn(appHooks, 'useAppDispatch').mockReturnValue(dispatch)
|
||||
sessionStorage.clear()
|
||||
Object.defineProperty(window, 'matchMedia', {
|
||||
writable: true,
|
||||
value: jest.fn().mockImplementation((query) => ({
|
||||
value: jest.fn().mockImplementation(query => ({
|
||||
matches: false,
|
||||
media: query,
|
||||
onchange: null,
|
||||
addEventListener: jest.fn(),
|
||||
removeEventListener: jest.fn(),
|
||||
dispatchEvent: jest.fn(),
|
||||
})),
|
||||
});
|
||||
});
|
||||
dispatchEvent: jest.fn()
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
test("redirects and sets sessionStorage when no userData", async () => {
|
||||
test('redirects and sets sessionStorage when no userData', async () => {
|
||||
const loginUrlMock = {
|
||||
code_verifier: "verifier123",
|
||||
state: "state123",
|
||||
redirectTo: new URL("http://login.url"),
|
||||
};
|
||||
code_verifier: 'verifier123',
|
||||
state: 'state123',
|
||||
redirectTo: new URL('http://login.url')
|
||||
}
|
||||
|
||||
jest.spyOn(oidcAuth, "Auth").mockResolvedValue(loginUrlMock);
|
||||
jest.spyOn(oidcAuth, 'Auth').mockResolvedValue(loginUrlMock)
|
||||
|
||||
const { result } = renderHook(() => useInitializeApp(), {
|
||||
wrapper: ({ children }) => (
|
||||
@@ -50,118 +50,118 @@ describe("HandleLogin", () => {
|
||||
tokens: null,
|
||||
loading: false,
|
||||
error: null,
|
||||
coreConfig: { language: "en" },
|
||||
coreConfig: { language: 'en' }
|
||||
},
|
||||
calendars: { list: {}, pending: false, error: null },
|
||||
calendars: { list: {}, pending: false, error: null }
|
||||
})}
|
||||
>
|
||||
{children}
|
||||
</Provider>
|
||||
),
|
||||
});
|
||||
)
|
||||
})
|
||||
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(oidcAuth.Auth).toHaveBeenCalled();
|
||||
expect(oidcAuth.Auth).toHaveBeenCalled()
|
||||
},
|
||||
{ timeout: 3000 }
|
||||
);
|
||||
)
|
||||
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(sessionStorage.getItem("redirectState")).toEqual(
|
||||
expect(sessionStorage.getItem('redirectState')).toEqual(
|
||||
JSON.stringify({
|
||||
code_verifier: "verifier123",
|
||||
state: "state123",
|
||||
code_verifier: 'verifier123',
|
||||
state: 'state123'
|
||||
})
|
||||
);
|
||||
)
|
||||
},
|
||||
{ timeout: 3000 }
|
||||
);
|
||||
)
|
||||
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(apiUtils.redirectTo).toHaveBeenCalledWith(
|
||||
loginUrlMock.redirectTo
|
||||
);
|
||||
)
|
||||
},
|
||||
{ timeout: 3000 }
|
||||
);
|
||||
});
|
||||
)
|
||||
})
|
||||
|
||||
test("does not render loading element when userData exists and calendars pending is true", () => {
|
||||
test('does not render loading element when userData exists and calendars pending is true', () => {
|
||||
const preloadedState = {
|
||||
user: {
|
||||
userData: {
|
||||
sub: "test",
|
||||
email: "test@test.com",
|
||||
sid: "aiYbWZSk2g0F+LrQeD7Dg4QcUMR8R/zTZdZBiA7N6Ro",
|
||||
openpaasId: "667037022b752d0026472254",
|
||||
sub: 'test',
|
||||
email: 'test@test.com',
|
||||
sid: 'aiYbWZSk2g0F+LrQeD7Dg4QcUMR8R/zTZdZBiA7N6Ro',
|
||||
openpaasId: '667037022b752d0026472254'
|
||||
},
|
||||
tokens: { access_token: "test" },
|
||||
loading: false,
|
||||
tokens: { access_token: 'test' },
|
||||
loading: false
|
||||
},
|
||||
calendars: { list: {}, pending: true },
|
||||
loading: { isLoading: true },
|
||||
};
|
||||
loading: { isLoading: true }
|
||||
}
|
||||
|
||||
renderWithProviders(<HandleLogin />, preloadedState);
|
||||
renderWithProviders(<HandleLogin />, preloadedState)
|
||||
// HandleLogin now returns null, loading is shown at App level via appLoading state
|
||||
expect(screen.queryByTestId("loading")).not.toBeInTheDocument();
|
||||
});
|
||||
test("does not render loading element when userData exists and calendars pending is false", () => {
|
||||
expect(screen.queryByTestId('loading')).not.toBeInTheDocument()
|
||||
})
|
||||
test('does not render loading element when userData exists and calendars pending is false', () => {
|
||||
const preloadedState = {
|
||||
user: {
|
||||
userData: {
|
||||
sub: "cmoussu",
|
||||
email: "cmoussu@linagora.com",
|
||||
sid: "aiYbWZSk2g0F+LrQeD7Dg4QcUMR8R/zTZdZBiA7N6Ro",
|
||||
openpaasId: "667037022b752d0026472254",
|
||||
sub: 'cmoussu',
|
||||
email: 'cmoussu@linagora.com',
|
||||
sid: 'aiYbWZSk2g0F+LrQeD7Dg4QcUMR8R/zTZdZBiA7N6Ro',
|
||||
openpaasId: '667037022b752d0026472254'
|
||||
},
|
||||
tokens: { access_token: "test" },
|
||||
loading: false,
|
||||
tokens: { access_token: 'test' },
|
||||
loading: false
|
||||
},
|
||||
calendars: { list: {}, pending: false },
|
||||
loading: { isLoading: false },
|
||||
};
|
||||
renderWithProviders(<HandleLogin />, preloadedState);
|
||||
loading: { isLoading: false }
|
||||
}
|
||||
renderWithProviders(<HandleLogin />, preloadedState)
|
||||
|
||||
// HandleLogin now returns null, loading is shown at App level via appLoading state
|
||||
expect(screen.queryByTestId("loading")).not.toBeInTheDocument();
|
||||
});
|
||||
test("goes to error page when there is error in user data", async () => {
|
||||
const mockDispatch = jest.fn();
|
||||
jest.spyOn(appHooks, "useAppDispatch").mockReturnValue(mockDispatch);
|
||||
jest.spyOn(oidcAuth, "Auth").mockResolvedValue({
|
||||
code_verifier: "verifier123",
|
||||
state: "state123",
|
||||
redirectTo: new URL("http://login.url"),
|
||||
});
|
||||
expect(screen.queryByTestId('loading')).not.toBeInTheDocument()
|
||||
})
|
||||
test('goes to error page when there is error in user data', async () => {
|
||||
const mockDispatch = jest.fn()
|
||||
jest.spyOn(appHooks, 'useAppDispatch').mockReturnValue(mockDispatch)
|
||||
jest.spyOn(oidcAuth, 'Auth').mockResolvedValue({
|
||||
code_verifier: 'verifier123',
|
||||
state: 'state123',
|
||||
redirectTo: new URL('http://login.url')
|
||||
})
|
||||
|
||||
renderWithProviders(<HandleLogin />, {
|
||||
user: {
|
||||
error: true,
|
||||
loading: false,
|
||||
userData: {
|
||||
sub: "test",
|
||||
email: "test@test.com",
|
||||
sid: "testSid",
|
||||
openpaasId: "testId",
|
||||
sub: 'test',
|
||||
email: 'test@test.com',
|
||||
sid: 'testSid',
|
||||
openpaasId: 'testId'
|
||||
},
|
||||
tokens: { access_token: "test" },
|
||||
tokens: { access_token: 'test' }
|
||||
},
|
||||
calendars: {
|
||||
list: {},
|
||||
pending: false,
|
||||
error: null,
|
||||
},
|
||||
});
|
||||
error: null
|
||||
}
|
||||
})
|
||||
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(mockDispatch).toHaveBeenCalledWith(push("/error"));
|
||||
expect(mockDispatch).toHaveBeenCalledWith(push('/error'))
|
||||
},
|
||||
{ timeout: 3000 }
|
||||
);
|
||||
});
|
||||
});
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,183 +1,182 @@
|
||||
import { useAppDispatch, useAppSelector } from "@/app/hooks";
|
||||
import { getCalendarsListAsync } from "@/features/Calendars/services/getCalendarsListAsync";
|
||||
import { CallbackResume } from "@/features/User/LoginCallback";
|
||||
import * as oidcAuth from "@/features/User/oidcAuth";
|
||||
import { useAppDispatch, useAppSelector } from '@/app/hooks'
|
||||
import { getCalendarsListAsync } from '@/features/Calendars/services/getCalendarsListAsync'
|
||||
import { CallbackResume } from '@/features/User/LoginCallback'
|
||||
import * as oidcAuth from '@/features/User/oidcAuth'
|
||||
import {
|
||||
getOpenPaasUserDataAsync,
|
||||
setTokens,
|
||||
setUserData,
|
||||
} from "@/features/User/userSlice";
|
||||
import { render, waitFor } from "@testing-library/react";
|
||||
import { replace } from "redux-first-history";
|
||||
import { renderWithProviders } from "../../utils/Renderwithproviders";
|
||||
import { setAppLoading } from "@/app/loadingSlice";
|
||||
setUserData
|
||||
} from '@/features/User/userSlice'
|
||||
import { render, waitFor } from '@testing-library/react'
|
||||
import { replace } from 'redux-first-history'
|
||||
import { renderWithProviders } from '../../utils/Renderwithproviders'
|
||||
import { setAppLoading } from '@/app/loadingSlice'
|
||||
|
||||
// Mocks
|
||||
jest.mock("@/app/hooks", () => ({
|
||||
jest.mock('@/app/hooks', () => ({
|
||||
useAppDispatch: jest.fn(),
|
||||
useAppSelector: jest.fn(() => ({
|
||||
user: {
|
||||
userData: null,
|
||||
tokens: null,
|
||||
loading: false,
|
||||
error: null,
|
||||
error: null
|
||||
},
|
||||
calendars: {
|
||||
list: {},
|
||||
pending: false,
|
||||
error: null,
|
||||
},
|
||||
})),
|
||||
}));
|
||||
error: null
|
||||
}
|
||||
}))
|
||||
}))
|
||||
|
||||
jest.mock("@/features/User/oidcAuth", () => ({
|
||||
Callback: jest.fn(),
|
||||
}));
|
||||
jest.mock('@/features/User/oidcAuth', () => ({
|
||||
Callback: jest.fn()
|
||||
}))
|
||||
|
||||
jest.mock("@/features/User/userSlice", () => {
|
||||
jest.mock('@/features/User/userSlice', () => {
|
||||
const mockGetUser = Object.assign(
|
||||
jest.fn(() => ({ type: "GET_USER_ID" })),
|
||||
jest.fn(() => ({ type: 'GET_USER_ID' })),
|
||||
{
|
||||
pending: { type: "GET_USER_ID/pending" },
|
||||
fulfilled: { type: "GET_USER_ID/fulfilled" },
|
||||
rejected: { type: "GET_USER_ID/rejected" },
|
||||
pending: { type: 'GET_USER_ID/pending' },
|
||||
fulfilled: { type: 'GET_USER_ID/fulfilled' },
|
||||
rejected: { type: 'GET_USER_ID/rejected' }
|
||||
}
|
||||
);
|
||||
)
|
||||
|
||||
return {
|
||||
setUserData: jest.fn((data) => ({ type: "SET_USER", payload: data })),
|
||||
setTokens: jest.fn((tokens) => ({ type: "SET_TOKENS", payload: tokens })),
|
||||
getOpenPaasUserDataAsync: mockGetUser,
|
||||
};
|
||||
});
|
||||
setUserData: jest.fn(data => ({ type: 'SET_USER', payload: data })),
|
||||
setTokens: jest.fn(tokens => ({ type: 'SET_TOKENS', payload: tokens })),
|
||||
getOpenPaasUserDataAsync: mockGetUser
|
||||
}
|
||||
})
|
||||
|
||||
jest.mock("@/features/Calendars/services/getCalendarsListAsync", () => {
|
||||
jest.mock('@/features/Calendars/services/getCalendarsListAsync', () => {
|
||||
const mockGetCalendars = Object.assign(
|
||||
jest.fn(() => ({ type: "GET_CALENDARS" })),
|
||||
jest.fn(() => ({ type: 'GET_CALENDARS' })),
|
||||
{
|
||||
pending: { type: "GET_CALENDARS/pending" },
|
||||
fulfilled: { type: "GET_CALENDARS/fulfilled" },
|
||||
rejected: { type: "GET_CALENDARS/rejected" },
|
||||
pending: { type: 'GET_CALENDARS/pending' },
|
||||
fulfilled: { type: 'GET_CALENDARS/fulfilled' },
|
||||
rejected: { type: 'GET_CALENDARS/rejected' }
|
||||
}
|
||||
);
|
||||
)
|
||||
|
||||
return {
|
||||
getCalendarsListAsync: mockGetCalendars,
|
||||
};
|
||||
});
|
||||
getCalendarsListAsync: mockGetCalendars
|
||||
}
|
||||
})
|
||||
|
||||
describe("CallbackResume", () => {
|
||||
const dispatch = jest.fn();
|
||||
let mockUserState: any;
|
||||
let mockCalendarsState: any;
|
||||
describe('CallbackResume', () => {
|
||||
const dispatch = jest.fn()
|
||||
let mockUserState: any
|
||||
let mockCalendarsState: any
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
(useAppDispatch as unknown as jest.Mock).mockReturnValue(dispatch);
|
||||
jest.clearAllMocks()
|
||||
;(useAppDispatch as unknown as jest.Mock).mockReturnValue(dispatch)
|
||||
|
||||
// Initialize mock states
|
||||
mockUserState = {
|
||||
userData: null,
|
||||
tokens: null,
|
||||
loading: false,
|
||||
error: null,
|
||||
};
|
||||
error: null
|
||||
}
|
||||
mockCalendarsState = {
|
||||
list: {},
|
||||
pending: false,
|
||||
error: null,
|
||||
};
|
||||
|
||||
(useAppSelector as jest.Mock).mockImplementation((selector) => {
|
||||
error: null
|
||||
}
|
||||
;(useAppSelector as jest.Mock).mockImplementation(selector => {
|
||||
const state = {
|
||||
user: mockUserState,
|
||||
calendars: mockCalendarsState,
|
||||
};
|
||||
return selector(state);
|
||||
});
|
||||
});
|
||||
calendars: mockCalendarsState
|
||||
}
|
||||
return selector(state)
|
||||
})
|
||||
})
|
||||
|
||||
it("should call Callback and dispatch necessary actions", async () => {
|
||||
const mockTokenSet = { access_token: "abc" };
|
||||
const mockUserInfo = { name: "Test User" };
|
||||
it('should call Callback and dispatch necessary actions', async () => {
|
||||
const mockTokenSet = { access_token: 'abc' }
|
||||
const mockUserInfo = { name: 'Test User' }
|
||||
|
||||
const mockData = {
|
||||
tokenSet: mockTokenSet,
|
||||
userinfo: mockUserInfo,
|
||||
};
|
||||
userinfo: mockUserInfo
|
||||
}
|
||||
|
||||
(oidcAuth.Callback as jest.Mock).mockResolvedValue(mockData);
|
||||
;(oidcAuth.Callback as jest.Mock).mockResolvedValue(mockData)
|
||||
|
||||
sessionStorage.setItem(
|
||||
"redirectState",
|
||||
JSON.stringify({ code_verifier: "verifier123", state: "state456" })
|
||||
);
|
||||
'redirectState',
|
||||
JSON.stringify({ code_verifier: 'verifier123', state: 'state456' })
|
||||
)
|
||||
|
||||
const { rerender } = render(<CallbackResume />);
|
||||
const { rerender } = render(<CallbackResume />)
|
||||
|
||||
await waitFor(() => {
|
||||
expect(oidcAuth.Callback).toHaveBeenCalledWith("verifier123", "state456");
|
||||
});
|
||||
expect(oidcAuth.Callback).toHaveBeenCalledWith('verifier123', 'state456')
|
||||
})
|
||||
await waitFor(() => {
|
||||
expect(dispatch).toHaveBeenCalledWith(setAppLoading(true));
|
||||
});
|
||||
expect(dispatch).toHaveBeenCalledWith(setAppLoading(true))
|
||||
})
|
||||
await waitFor(() => {
|
||||
expect(dispatch).toHaveBeenCalledWith(setUserData(mockUserInfo));
|
||||
});
|
||||
expect(dispatch).toHaveBeenCalledWith(setUserData(mockUserInfo))
|
||||
})
|
||||
await waitFor(() => {
|
||||
expect(dispatch).toHaveBeenCalledWith(setTokens(mockTokenSet));
|
||||
});
|
||||
expect(dispatch).toHaveBeenCalledWith(setTokens(mockTokenSet))
|
||||
})
|
||||
await waitFor(() => {
|
||||
expect(dispatch).toHaveBeenCalledWith(getOpenPaasUserDataAsync());
|
||||
});
|
||||
expect(dispatch).toHaveBeenCalledWith(getOpenPaasUserDataAsync())
|
||||
})
|
||||
await waitFor(() => {
|
||||
expect(dispatch).toHaveBeenCalledWith(getCalendarsListAsync());
|
||||
});
|
||||
expect(dispatch).toHaveBeenCalledWith(getCalendarsListAsync())
|
||||
})
|
||||
|
||||
// Simulate async actions completing by updating mock state
|
||||
mockUserState = {
|
||||
userData: mockUserInfo,
|
||||
tokens: mockTokenSet,
|
||||
loading: false,
|
||||
error: null,
|
||||
};
|
||||
error: null
|
||||
}
|
||||
mockCalendarsState = {
|
||||
list: { calendar1: {} },
|
||||
pending: false,
|
||||
error: null,
|
||||
};
|
||||
error: null
|
||||
}
|
||||
|
||||
// Re-render to trigger navigation effect
|
||||
rerender(<CallbackResume />);
|
||||
rerender(<CallbackResume />)
|
||||
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(dispatch).toHaveBeenCalledWith(setAppLoading(false));
|
||||
expect(dispatch).toHaveBeenCalledWith(setAppLoading(false))
|
||||
},
|
||||
{ timeout: 3000 }
|
||||
);
|
||||
)
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(dispatch).toHaveBeenCalledWith(replace("/calendar"));
|
||||
expect(dispatch).toHaveBeenCalledWith(replace('/calendar'))
|
||||
},
|
||||
{ timeout: 3000 }
|
||||
);
|
||||
)
|
||||
await waitFor(() => {
|
||||
expect(sessionStorage.getItem("redirectState")).toBe(null);
|
||||
});
|
||||
expect(sessionStorage.getItem('redirectState')).toBe(null)
|
||||
})
|
||||
await waitFor(() => {
|
||||
expect(sessionStorage.getItem("tokenSet")).toEqual(
|
||||
expect(sessionStorage.getItem('tokenSet')).toEqual(
|
||||
JSON.stringify(mockTokenSet)
|
||||
);
|
||||
});
|
||||
});
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it("should handle missing redirectState gracefully", async () => {
|
||||
sessionStorage.removeItem("redirectState");
|
||||
renderWithProviders(<CallbackResume />);
|
||||
it('should handle missing redirectState gracefully', async () => {
|
||||
sessionStorage.removeItem('redirectState')
|
||||
renderWithProviders(<CallbackResume />)
|
||||
|
||||
await waitFor(() => {
|
||||
expect(dispatch).toHaveBeenCalledWith(replace("/"));
|
||||
});
|
||||
});
|
||||
});
|
||||
expect(dispatch).toHaveBeenCalledWith(replace('/'))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -4,169 +4,168 @@ import {
|
||||
Callback,
|
||||
clientConfig,
|
||||
getClientConfig,
|
||||
Logout,
|
||||
} from "@/features/User/oidcAuth";
|
||||
import * as apiUtils from "@/utils/apiUtils";
|
||||
import * as client from "openid-client";
|
||||
Logout
|
||||
} from '@/features/User/oidcAuth'
|
||||
import * as apiUtils from '@/utils/apiUtils'
|
||||
import * as client from 'openid-client'
|
||||
|
||||
clientConfig.url = "https://example.com";
|
||||
const localAdress = "https://local.exemple.com";
|
||||
clientConfig.url = 'https://example.com'
|
||||
const localAdress = 'https://local.exemple.com'
|
||||
|
||||
describe("OpenID Client Auth Module", () => {
|
||||
describe('OpenID Client Auth Module', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
jest.spyOn(apiUtils, "getLocation").mockImplementation(() => localAdress);
|
||||
});
|
||||
jest.clearAllMocks()
|
||||
jest.spyOn(apiUtils, 'getLocation').mockImplementation(() => localAdress)
|
||||
})
|
||||
|
||||
describe("getClientConfig", () => {
|
||||
it("should call discovery with clientConfig.url", async () => {
|
||||
const discoveryMock = client.discovery as jest.Mock;
|
||||
discoveryMock.mockResolvedValue("discoveredClient");
|
||||
describe('getClientConfig', () => {
|
||||
it('should call discovery with clientConfig.url', async () => {
|
||||
const discoveryMock = client.discovery as jest.Mock
|
||||
discoveryMock.mockResolvedValue('discoveredClient')
|
||||
|
||||
const result = await getClientConfig();
|
||||
const result = await getClientConfig()
|
||||
|
||||
expect(discoveryMock).toHaveBeenCalledWith(
|
||||
new URL(clientConfig.url),
|
||||
clientConfig.client_id
|
||||
);
|
||||
expect(result).toBe("discoveredClient");
|
||||
});
|
||||
});
|
||||
)
|
||||
expect(result).toBe('discoveredClient')
|
||||
})
|
||||
})
|
||||
|
||||
describe("Auth", () => {
|
||||
it("should generate PKCE and build authorization URL with PKCE", async () => {
|
||||
(client.randomPKCECodeVerifier as jest.Mock).mockReturnValue(
|
||||
"verifier123"
|
||||
);
|
||||
(client.calculatePKCECodeChallenge as jest.Mock).mockResolvedValue(
|
||||
"challenge123"
|
||||
);
|
||||
describe('Auth', () => {
|
||||
it('should generate PKCE and build authorization URL with PKCE', async () => {
|
||||
;(client.randomPKCECodeVerifier as jest.Mock).mockReturnValue(
|
||||
'verifier123'
|
||||
)
|
||||
;(client.calculatePKCECodeChallenge as jest.Mock).mockResolvedValue(
|
||||
'challenge123'
|
||||
)
|
||||
|
||||
// Mock discovery returning an object with serverMetadata()
|
||||
const discoveredClient = {
|
||||
serverMetadata: jest.fn(() => ({
|
||||
supportsPKCE: () => true,
|
||||
})),
|
||||
};
|
||||
(client.discovery as jest.Mock).mockResolvedValue(discoveredClient);
|
||||
supportsPKCE: () => true
|
||||
}))
|
||||
}
|
||||
;(client.discovery as jest.Mock).mockResolvedValue(discoveredClient)
|
||||
;(client.buildAuthorizationUrl as jest.Mock).mockReturnValue(
|
||||
'https://auth.url'
|
||||
)
|
||||
|
||||
(client.buildAuthorizationUrl as jest.Mock).mockReturnValue(
|
||||
"https://auth.url"
|
||||
);
|
||||
const result = await Auth()
|
||||
|
||||
const result = await Auth();
|
||||
|
||||
expect(client.randomPKCECodeVerifier).toHaveBeenCalled();
|
||||
expect(client.randomPKCECodeVerifier).toHaveBeenCalled()
|
||||
expect(client.calculatePKCECodeChallenge).toHaveBeenCalledWith(
|
||||
"verifier123"
|
||||
);
|
||||
'verifier123'
|
||||
)
|
||||
expect(client.buildAuthorizationUrl).toHaveBeenCalledWith(
|
||||
discoveredClient,
|
||||
expect.objectContaining({
|
||||
code_challenge: "challenge123",
|
||||
code_challenge: 'challenge123',
|
||||
code_challenge_method: clientConfig.code_challenge_method,
|
||||
redirect_uri: clientConfig.redirect_uri,
|
||||
scope: clientConfig.scope,
|
||||
scope: clientConfig.scope
|
||||
})
|
||||
);
|
||||
)
|
||||
expect(result).toEqual({
|
||||
redirectTo: "https://auth.url",
|
||||
code_verifier: "verifier123",
|
||||
state: undefined,
|
||||
});
|
||||
});
|
||||
redirectTo: 'https://auth.url',
|
||||
code_verifier: 'verifier123',
|
||||
state: undefined
|
||||
})
|
||||
})
|
||||
|
||||
it("should generate state when PKCE not supported", async () => {
|
||||
(client.randomPKCECodeVerifier as jest.Mock).mockReturnValue(
|
||||
"verifier123"
|
||||
);
|
||||
(client.calculatePKCECodeChallenge as jest.Mock).mockResolvedValue(
|
||||
"challenge123"
|
||||
);
|
||||
it('should generate state when PKCE not supported', async () => {
|
||||
;(client.randomPKCECodeVerifier as jest.Mock).mockReturnValue(
|
||||
'verifier123'
|
||||
)
|
||||
;(client.calculatePKCECodeChallenge as jest.Mock).mockResolvedValue(
|
||||
'challenge123'
|
||||
)
|
||||
|
||||
const discoveredClient = {
|
||||
serverMetadata: jest.fn(() => ({
|
||||
supportsPKCE: () => false,
|
||||
})),
|
||||
};
|
||||
(client.discovery as jest.Mock).mockResolvedValue(discoveredClient);
|
||||
(client.randomState as jest.Mock).mockReturnValue("state123");
|
||||
(client.buildAuthorizationUrl as jest.Mock).mockReturnValue(
|
||||
"https://auth.url"
|
||||
);
|
||||
supportsPKCE: () => false
|
||||
}))
|
||||
}
|
||||
;(client.discovery as jest.Mock).mockResolvedValue(discoveredClient)
|
||||
;(client.randomState as jest.Mock).mockReturnValue('state123')
|
||||
;(client.buildAuthorizationUrl as jest.Mock).mockReturnValue(
|
||||
'https://auth.url'
|
||||
)
|
||||
|
||||
const result = await Auth();
|
||||
const result = await Auth()
|
||||
|
||||
expect(client.randomState).toHaveBeenCalled();
|
||||
expect(result.state).toBe("state123");
|
||||
expect(result.redirectTo).toBe("https://auth.url");
|
||||
});
|
||||
});
|
||||
expect(client.randomState).toHaveBeenCalled()
|
||||
expect(result.state).toBe('state123')
|
||||
expect(result.redirectTo).toBe('https://auth.url')
|
||||
})
|
||||
})
|
||||
|
||||
describe("Logout", () => {
|
||||
it("should build end session URL", async () => {
|
||||
const discoveredClient = {};
|
||||
(client.discovery as jest.Mock).mockResolvedValue(discoveredClient);
|
||||
(client.buildEndSessionUrl as jest.Mock).mockReturnValue(
|
||||
"https://logout.url"
|
||||
);
|
||||
describe('Logout', () => {
|
||||
it('should build end session URL', async () => {
|
||||
const discoveredClient = {}
|
||||
;(client.discovery as jest.Mock).mockResolvedValue(discoveredClient)
|
||||
;(client.buildEndSessionUrl as jest.Mock).mockReturnValue(
|
||||
'https://logout.url'
|
||||
)
|
||||
|
||||
const result = await Logout();
|
||||
const result = await Logout()
|
||||
|
||||
expect(client.buildEndSessionUrl).toHaveBeenCalledWith(discoveredClient, {
|
||||
post_logout_redirect_uri: clientConfig.post_logout_redirect_uri,
|
||||
});
|
||||
expect(result).toBe("https://logout.url");
|
||||
});
|
||||
});
|
||||
post_logout_redirect_uri: clientConfig.post_logout_redirect_uri
|
||||
})
|
||||
expect(result).toBe('https://logout.url')
|
||||
})
|
||||
})
|
||||
|
||||
describe("Callback", () => {
|
||||
it("should perform authorization code grant and fetch user info", async () => {
|
||||
const discoveredClient = {};
|
||||
(client.discovery as jest.Mock).mockResolvedValue(discoveredClient);
|
||||
describe('Callback', () => {
|
||||
it('should perform authorization code grant and fetch user info', async () => {
|
||||
const discoveredClient = {}
|
||||
;(client.discovery as jest.Mock).mockResolvedValue(discoveredClient)
|
||||
|
||||
const mockTokenSet = {
|
||||
access_token: "access123",
|
||||
claims: jest.fn(() => ({ sub: "user123" })),
|
||||
};
|
||||
(client.authorizationCodeGrant as jest.Mock).mockResolvedValue(
|
||||
access_token: 'access123',
|
||||
claims: jest.fn(() => ({ sub: 'user123' }))
|
||||
}
|
||||
;(client.authorizationCodeGrant as jest.Mock).mockResolvedValue(
|
||||
mockTokenSet
|
||||
);
|
||||
(client.fetchUserInfo as jest.Mock).mockResolvedValue({ name: "User" });
|
||||
const result = await Callback("verifier123", "state123");
|
||||
)
|
||||
;(client.fetchUserInfo as jest.Mock).mockResolvedValue({ name: 'User' })
|
||||
const result = await Callback('verifier123', 'state123')
|
||||
|
||||
expect(client.authorizationCodeGrant).toHaveBeenCalledWith(
|
||||
discoveredClient,
|
||||
new URL(localAdress),
|
||||
{ pkceCodeVerifier: "verifier123", expectedState: "state123" }
|
||||
);
|
||||
{ pkceCodeVerifier: 'verifier123', expectedState: 'state123' }
|
||||
)
|
||||
|
||||
expect(client.fetchUserInfo).toHaveBeenCalledWith(
|
||||
discoveredClient,
|
||||
"access123",
|
||||
"user123"
|
||||
);
|
||||
'access123',
|
||||
'user123'
|
||||
)
|
||||
|
||||
expect(result).toEqual({
|
||||
tokenSet: mockTokenSet,
|
||||
userinfo: { name: "User" },
|
||||
});
|
||||
});
|
||||
userinfo: { name: 'User' }
|
||||
})
|
||||
})
|
||||
|
||||
it("should catch and log errors", async () => {
|
||||
const error = new Error("fail");
|
||||
(client.discovery as jest.Mock).mockResolvedValue({});
|
||||
(client.authorizationCodeGrant as jest.Mock).mockRejectedValue(error);
|
||||
it('should catch and log errors', async () => {
|
||||
const error = new Error('fail')
|
||||
;(client.discovery as jest.Mock).mockResolvedValue({})
|
||||
;(client.authorizationCodeGrant as jest.Mock).mockRejectedValue(error)
|
||||
const consoleErrorSpy = jest
|
||||
.spyOn(console, "error")
|
||||
.mockImplementation(() => {});
|
||||
.spyOn(console, 'error')
|
||||
.mockImplementation(() => {})
|
||||
|
||||
const result = await Callback("verifier", "state");
|
||||
const result = await Callback('verifier', 'state')
|
||||
|
||||
expect(consoleErrorSpy).toHaveBeenCalledWith("Token grant error:", error);
|
||||
expect(result).toBeUndefined();
|
||||
expect(consoleErrorSpy).toHaveBeenCalledWith('Token grant error:', error)
|
||||
expect(result).toBeUndefined()
|
||||
|
||||
consoleErrorSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
});
|
||||
consoleErrorSpy.mockRestore()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,114 +1,114 @@
|
||||
import { clientConfig } from "@/features/User/oidcAuth";
|
||||
import { clientConfig } from '@/features/User/oidcAuth'
|
||||
import {
|
||||
getOpenPaasUser,
|
||||
updateUserConfigurations,
|
||||
getResourceDetails,
|
||||
getUserDetails,
|
||||
} from "@/features/User/userAPI";
|
||||
import { api } from "@/utils/apiUtils";
|
||||
getUserDetails
|
||||
} from '@/features/User/userAPI'
|
||||
import { api } from '@/utils/apiUtils'
|
||||
|
||||
jest.mock("@/utils/apiUtils");
|
||||
jest.mock('@/utils/apiUtils')
|
||||
|
||||
clientConfig.url = "https://example.com";
|
||||
clientConfig.url = 'https://example.com'
|
||||
|
||||
describe("getOpenPaasUser", () => {
|
||||
it("should fetch and return user data", async () => {
|
||||
const mockUser = { id: "123", name: "OpenPaas User" };
|
||||
describe('getOpenPaasUser', () => {
|
||||
it('should fetch and return user data', async () => {
|
||||
const mockUser = { id: '123', name: 'OpenPaas User' }
|
||||
|
||||
(api.get as jest.Mock).mockReturnValue({
|
||||
json: jest.fn().mockResolvedValue(mockUser),
|
||||
});
|
||||
;(api.get as jest.Mock).mockReturnValue({
|
||||
json: jest.fn().mockResolvedValue(mockUser)
|
||||
})
|
||||
|
||||
const result = await getOpenPaasUser();
|
||||
const result = await getOpenPaasUser()
|
||||
|
||||
expect(api.get).toHaveBeenCalledWith("api/user");
|
||||
expect(result).toEqual(mockUser);
|
||||
});
|
||||
});
|
||||
expect(api.get).toHaveBeenCalledWith('api/user')
|
||||
expect(result).toEqual(mockUser)
|
||||
})
|
||||
})
|
||||
|
||||
describe("getUserDetails", () => {
|
||||
it("should fetch and return user details", async () => {
|
||||
describe('getUserDetails', () => {
|
||||
it('should fetch and return user details', async () => {
|
||||
const mockUser = {
|
||||
firstname: "John",
|
||||
lastname: "Doe",
|
||||
emails: ["john@test.com"],
|
||||
};
|
||||
const userId = "123";
|
||||
firstname: 'John',
|
||||
lastname: 'Doe',
|
||||
emails: ['john@test.com']
|
||||
}
|
||||
const userId = '123'
|
||||
|
||||
(api.get as jest.Mock).mockReturnValue({
|
||||
json: jest.fn().mockResolvedValue(mockUser),
|
||||
});
|
||||
;(api.get as jest.Mock).mockReturnValue({
|
||||
json: jest.fn().mockResolvedValue(mockUser)
|
||||
})
|
||||
|
||||
const result = await getUserDetails(userId);
|
||||
const result = await getUserDetails(userId)
|
||||
|
||||
expect(api.get).toHaveBeenCalledWith(`api/users/${userId}`);
|
||||
expect(result).toEqual(mockUser);
|
||||
});
|
||||
});
|
||||
expect(api.get).toHaveBeenCalledWith(`api/users/${userId}`)
|
||||
expect(result).toEqual(mockUser)
|
||||
})
|
||||
})
|
||||
|
||||
describe("getResourceDetails", () => {
|
||||
it("should fetch and return resource details", async () => {
|
||||
const mockResource = { _id: "res-123", name: "Meeting Room A" };
|
||||
const resourceId = "res-123";
|
||||
describe('getResourceDetails', () => {
|
||||
it('should fetch and return resource details', async () => {
|
||||
const mockResource = { _id: 'res-123', name: 'Meeting Room A' }
|
||||
const resourceId = 'res-123'
|
||||
|
||||
(api.get as jest.Mock).mockReturnValue({
|
||||
json: jest.fn().mockResolvedValue(mockResource),
|
||||
});
|
||||
;(api.get as jest.Mock).mockReturnValue({
|
||||
json: jest.fn().mockResolvedValue(mockResource)
|
||||
})
|
||||
|
||||
const result = await getResourceDetails(resourceId);
|
||||
const result = await getResourceDetails(resourceId)
|
||||
|
||||
expect(api.get).toHaveBeenCalledWith(`api/resources/${resourceId}`);
|
||||
expect(result).toEqual(mockResource);
|
||||
});
|
||||
});
|
||||
expect(api.get).toHaveBeenCalledWith(`api/resources/${resourceId}`)
|
||||
expect(result).toEqual(mockResource)
|
||||
})
|
||||
})
|
||||
|
||||
describe("updateUserConfigurations", () => {
|
||||
describe('updateUserConfigurations', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
it("should PATCH configurations with language update", async () => {
|
||||
const mockResponse = { status: 204 };
|
||||
(api.patch as jest.Mock).mockResolvedValue(mockResponse);
|
||||
it('should PATCH configurations with language update', async () => {
|
||||
const mockResponse = { status: 204 }
|
||||
;(api.patch as jest.Mock).mockResolvedValue(mockResponse)
|
||||
|
||||
await updateUserConfigurations({ language: "vi" });
|
||||
await updateUserConfigurations({ language: 'vi' })
|
||||
|
||||
expect(api.patch).toHaveBeenCalledWith("api/configurations?scope=user", {
|
||||
expect(api.patch).toHaveBeenCalledWith('api/configurations?scope=user', {
|
||||
json: [
|
||||
{
|
||||
name: "core",
|
||||
configurations: [{ name: "language", value: "vi" }],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
name: 'core',
|
||||
configurations: [{ name: 'language', value: 'vi' }]
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
|
||||
it("should PATCH configurations with multiple updates", async () => {
|
||||
const mockResponse = { status: 204 };
|
||||
(api.patch as jest.Mock).mockResolvedValue(mockResponse);
|
||||
it('should PATCH configurations with multiple updates', async () => {
|
||||
const mockResponse = { status: 204 }
|
||||
;(api.patch as jest.Mock).mockResolvedValue(mockResponse)
|
||||
|
||||
await updateUserConfigurations({
|
||||
language: "fr",
|
||||
timezone: "Europe/Paris",
|
||||
});
|
||||
language: 'fr',
|
||||
timezone: 'Europe/Paris'
|
||||
})
|
||||
|
||||
expect(api.patch).toHaveBeenCalledWith("api/configurations?scope=user", {
|
||||
expect(api.patch).toHaveBeenCalledWith('api/configurations?scope=user', {
|
||||
json: [
|
||||
{
|
||||
name: "core",
|
||||
name: 'core',
|
||||
configurations: [
|
||||
{ name: "language", value: "fr" },
|
||||
{ name: "datetime", value: { timeZone: "Europe/Paris" } },
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
{ name: 'language', value: 'fr' },
|
||||
{ name: 'datetime', value: { timeZone: 'Europe/Paris' } }
|
||||
]
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
|
||||
it("should handle empty updates without calling API", async () => {
|
||||
const result = await updateUserConfigurations({});
|
||||
it('should handle empty updates without calling API', async () => {
|
||||
const result = await updateUserConfigurations({})
|
||||
|
||||
expect(api.patch).not.toHaveBeenCalled();
|
||||
expect(result).toEqual({ status: 204 });
|
||||
});
|
||||
});
|
||||
expect(api.patch).not.toHaveBeenCalled()
|
||||
expect(result).toEqual({ status: 204 })
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user