From 7188fcfb678b15effc056174f26d565f200cf6b4 Mon Sep 17 00:00:00 2001 From: tysky Date: Mon, 20 Nov 2023 10:26:52 +0300 Subject: [PATCH] add tests --- dist/auther-client.cjs.js | 5 +- dist/auther-client.es.js | 5 +- src/client/AutherClient.js | 1 - tests/client.test.js | 148 ++++++++++++++++++++++++++++--------- 4 files changed, 118 insertions(+), 41 deletions(-) diff --git a/dist/auther-client.cjs.js b/dist/auther-client.cjs.js index 4ea6e54..2a7b045 100644 --- a/dist/auther-client.cjs.js +++ b/dist/auther-client.cjs.js @@ -657,14 +657,13 @@ var AutherClient = /*#__PURE__*/_createClass(function AutherClient(_ref) { getTokens: getTokens, saveTokens: saveTokens }); - _context2.next = 10; + _context2.next = 9; break; case 6: _context2.prev = 6; _context2.t0 = _context2["catch"](0); _this.logger.error("Error during tokens refreshing at ".concat(new Date(), " [").concat(new Date().toUTCString(), "]")); - throw _context2.t0; - case 10: + case 9: case "end": return _context2.stop(); } diff --git a/dist/auther-client.es.js b/dist/auther-client.es.js index 678cb28..3523aa8 100644 --- a/dist/auther-client.es.js +++ b/dist/auther-client.es.js @@ -655,14 +655,13 @@ var AutherClient = /*#__PURE__*/_createClass(function AutherClient(_ref) { getTokens: getTokens, saveTokens: saveTokens }); - _context2.next = 10; + _context2.next = 9; break; case 6: _context2.prev = 6; _context2.t0 = _context2["catch"](0); _this.logger.error("Error during tokens refreshing at ".concat(new Date(), " [").concat(new Date().toUTCString(), "]")); - throw _context2.t0; - case 10: + case 9: case "end": return _context2.stop(); } diff --git a/src/client/AutherClient.js b/src/client/AutherClient.js index 59d19fd..3e7caa1 100644 --- a/src/client/AutherClient.js +++ b/src/client/AutherClient.js @@ -75,7 +75,6 @@ export class AutherClient { this.logger.error( `Error during tokens refreshing at ${new Date()} [${new Date().toUTCString()}]`, ) - throw error } }, refreshTimeout) } diff --git a/tests/client.test.js b/tests/client.test.js index 4399bf6..947c237 100644 --- a/tests/client.test.js +++ b/tests/client.test.js @@ -12,38 +12,54 @@ const APPCODE = "appcode" const AUTHER_URL = "http://localhost/" const TEST_AUTHORIZATION_CODE = "75e1cece-2991-4be5-9fb4-c6968e5f3311" -const createAutherClient = () => { +const createAutherClient = (params = {}) => { return AutherClient.init({ autherUrl: AUTHER_URL, redirectUri: RETURN_URI, appcode: APPCODE, http: doFetch(AUTHER_URL), + ...params, }) } const getTokenPayload = expDate => { const expiredAt = expDate ? new Date(expDate) : new Date() const issuedAt = new Date(expiredAt) - expiredAt.setHours(expiredAt.getHours() + 1) + if (!expDate) { + expiredAt.setHours(expiredAt.getHours() + 1) + } const iat = issuedAt.getTime() / 1000 // in seconds const exp = expiredAt.getTime() / 1000 // in seconds return { iat, exp } } const getToken = (params = {}) => { - const payload = btoa(JSON.stringify({ ...getTokenPayload(), ...params })) + const { expDate, type } = params + const payload = btoa(JSON.stringify({ ...getTokenPayload(expDate), type })) const header = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" const signature = "SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" const jwtLikeToken = `${header}.${payload}.${signature}` return jwtLikeToken } -const getAccessToken = (params = {}) => { - return getToken({ type: "access", ...params }) +const getAccessToken = expDate => { + return getToken({ type: "access", expDate }) } -const getRefreshToken = (params = {}) => { - return getToken({ type: "refresh", ...params }) +const getRefreshToken = expDate => { + return getToken({ type: "refresh", expDate }) +} + +const getAuthCallbacks = ({ accessTokenExpDate, refreshTokenExpDate } = {}) => { + let accessToken = getAccessToken(accessTokenExpDate) + let refreshToken = getRefreshToken(refreshTokenExpDate) + const getTokens = () => ({ accessToken, refreshToken }) + const saveTokens = (tokens = {}) => { + if (tokens.accessToken) accessToken = tokens.accessToken + if (tokens.refreshToken) refreshToken = tokens.refreshToken + } + + return { getTokens, saveTokens } } describe("When use auther methods", () => { @@ -125,25 +141,25 @@ describe("When use auther methods", () => { }) describe("authenticate method", () => { + beforeEach(() => { + jest.useFakeTimers() + }) + it("should authenticate with fresh tokens", async () => { fetch.mockResponseOnce(JSON.stringify({ accessToken: getAccessToken(), refreshToken: getRefreshToken(), })) - jest.useFakeTimers() const auth = createAutherClient() - const accessToken = getAccessToken() - const refreshToken = getRefreshToken() - const getTokens = () => ({ accessToken, refreshToken }) - const saveTokens = () => {} + const callbacks = getAuthCallbacks() - await expect(() => auth.authentication({ getTokens, saveTokens })).not.toThrowError() + await expect(() => auth.authentication(callbacks)).not.toThrowError() jest.runOnlyPendingTimers() const expectedUrl = "http://localhost/tokens/refresh" - const expectedBody = JSON.stringify({ refreshToken }) + const expectedBody = JSON.stringify({ refreshToken: callbacks.getTokens().refreshToken }) const expectedHeaders = { "Content-Type": "application/json", Accept: "application/json", @@ -161,26 +177,18 @@ describe("When use auther methods", () => { accessToken: getAccessToken(), refreshToken: getRefreshToken(), })) - jest.useFakeTimers() const auth = createAutherClient() const expiredDate = new Date() expiredDate.setHours(expiredDate.getHours() - 3) - let accessToken = getAccessToken(getTokenPayload(expiredDate)) - let refreshToken = getRefreshToken() - const getTokens = () => ({ accessToken, refreshToken }) - const saveTokens = (tokens = {}) => { - if (tokens.accessToken) accessToken = tokens.accessToken - if (tokens.refreshToken) refreshToken = tokens.refreshToken - } - - await expect(() => auth.authentication({ getTokens, saveTokens })).not.toThrowError() + const callbacks = getAuthCallbacks({ accessTokenExpDate: expiredDate }) + await expect(() => auth.authentication(callbacks)).not.toThrowError() jest.runOnlyPendingTimers() const expectedUrl = "http://localhost/tokens/refresh" - const expectedBody = JSON.stringify({ refreshToken }) + const expectedBody = JSON.stringify({ refreshToken: callbacks.getTokens().refreshToken }) const expectedHeaders = { "Content-Type": "application/json", Accept: "application/json", @@ -193,25 +201,97 @@ describe("When use auther methods", () => { }) }) + it("should log error when refresh token expired", async () => { + fetch.mockResponseOnce(JSON.stringify({ + accessToken: getAccessToken(), + refreshToken: getRefreshToken(), + })) + const mockLogger = { log: jest.fn(), error: jest.fn() } + + const auth = createAutherClient({ logger: mockLogger }) + const expiredDate = new Date() + expiredDate.setHours(expiredDate.getHours() - 3) + const callbacks = getAuthCallbacks({ refreshTokenExpDate: expiredDate }) + + await expect(() => auth.authentication(callbacks)).not.toThrowError() + + jest.runAllTimers() + + mockLogger.error.mockImplementationOnce(() => { + expect(mockLogger.error).toHaveBeenCalledWith( + `Error during tokens refreshing at ${new Date()} [${new Date().toUTCString()}]`, + ) + }) + }) + it("should throw error when both tokens expired", async () => { const auth = createAutherClient() const expiredDate = new Date() expiredDate.setHours(expiredDate.getHours() - 3) - let accessToken = getAccessToken(getTokenPayload(expiredDate)) - let refreshToken = getRefreshToken(getTokenPayload(expiredDate)) - - const getTokens = () => ({ accessToken, refreshToken }) - const saveTokens = (tokens = {}) => { - if (tokens.accessToken) accessToken = tokens.accessToken - if (tokens.refreshToken) refreshToken = tokens.refreshToken - } + const callbacks = getAuthCallbacks({ + accessTokenExpDate: expiredDate, + refreshTokenExpDate: expiredDate, + }) - await expect(() => auth.authentication({ getTokens, saveTokens })) + await expect(() => auth.authentication(callbacks)) .rejects .toThrow("token.expired") expect(fetch).not.toHaveBeenCalled() }) + + it("should log error when server fails to refresh tokens", async () => { + const mockLogger = { log: jest.fn(), error: jest.fn() } + const auth = createAutherClient({ logger: mockLogger }) + + fetch.mockRejectOnce() + + const callbacks = getAuthCallbacks() + + await expect(() => auth.authentication(callbacks)).not.toThrowError() + + jest.runAllTimers() + + mockLogger.error.mockImplementationOnce(() => { + expect(mockLogger.error).toHaveBeenCalledWith( + `Error during tokens refreshing at ${new Date()} [${new Date().toUTCString()}]`, + ) + }) + }) + + it("should set min refreshTimeout to one minute", async () => { + const mockLogger = { log: jest.fn() } + + const auth = createAutherClient({ logger: mockLogger }) + const expiredDate = new Date() + expiredDate.setSeconds(expiredDate.getSeconds() + 30) + const callbacks = getAuthCallbacks({ accessTokenExpDate: expiredDate }) + + await auth.authentication(callbacks) + + const expectedRefreshDate = new Date(Date.now() + 60 * 1000) // one minute + + expect(mockLogger.log).toHaveBeenCalledWith( + `Token will be refreshed at ${expectedRefreshDate} [${expectedRefreshDate.toUTCString()}]`, + ) + }) + + it("should set max refreshTimeout to one day", async () => { + const mockLogger = { log: jest.fn() } + + const auth = createAutherClient({ logger: mockLogger }) + const expiredDate = new Date() + expiredDate.setDate(expiredDate.getDate() + 10) + const callbacks = getAuthCallbacks({ accessTokenExpDate: expiredDate }) + + await auth.authentication(callbacks) + + const expectedRefreshDate = new Date(Date.now() + 24 * 60 * 60 * 1000) // one day + + expect(mockLogger.log).toHaveBeenCalledWith( + `Token will be refreshed at ${expectedRefreshDate} [${expectedRefreshDate.toUTCString()}]`, + ) + }) }) })