diff --git a/__tests__/lhisp-oauth-client.test.ts b/__tests__/lhisp-oauth-client.test.ts index b5909c6..63bb50c 100644 --- a/__tests__/lhisp-oauth-client.test.ts +++ b/__tests__/lhisp-oauth-client.test.ts @@ -1,6 +1,6 @@ import axios from 'axios'; -import LhispOauthClient from "../src/lhisp-oauth-client"; -import { LhispOauthClientConstructorParams } from '../src/lhisp-oauth-client.t'; +import { LhispOauthClient } from "../src/lhisp-oauth-client"; +import { ContentType, LhispOauthClientConstructorParams } from '../src/lhisp-oauth-client.t'; // Mock jest and set the type jest.mock('axios'); @@ -13,34 +13,20 @@ const clientSecret = "testClientSecret"; const baseClientParams = { apiUrl, authUrl, clientId, clientSecret }; const basicAuth = `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`; const contentTypeApplicationJson = "application/json"; +const contentTypeApplicationXFormUrlEncoded = "application/x-www-form-urlencoded"; const defaultGrantValue='client_credentials'; const defaultGrantType=`{"grant_type":"${defaultGrantValue}"}`; describe("Get Access Token", ()=>{ + beforeEach(() => { + mockedAxios.request.mockReset(); + mockedAxios.request.mockResolvedValueOnce({ data: mockedAccessToken }); + }); + it("Shoud Get with Standard Config", async ()=>{ const cli = getOauthClient(); - mockedAxios.request.mockReset(); - mockedAxios.request.mockResolvedValueOnce({ - data: mockedAccessToken - }); - - const now = Date.now(); - const accessToken = await cli.getAccessToken(); - expect(accessToken).toBeDefined(); - expect(accessToken.token_type).toBe(mockedAccessToken.token_type); - expect(accessToken.access_token).toBe(mockedAccessToken.access_token); - expect(accessToken.expires_in).toBe(mockedAccessToken.expires_in); - expect(accessToken.scope).toBe(mockedAccessToken.scope); - expect(accessToken.created_at).toBeGreaterThanOrEqual(now); - expect(mockedAxios.request).toBeCalledWith(expect.objectContaining({ - url: authUrl, - method: "POST", - headers: { - Authorization: basicAuth, - 'Content-Type': contentTypeApplicationJson, - }, - data: defaultGrantType, - })); + await accessTokenValidator(cli); + validateDefaultGetAccessToken(); }); it("Shoud Get with Custom Auth Header", async ()=>{ @@ -48,19 +34,7 @@ describe("Get Access Token", ()=>{ ...baseClientParams, authHeaderName: 'CustomAuthorizationHeader', }); - mockedAxios.request.mockReset(); - mockedAxios.request.mockResolvedValueOnce({ - data: mockedAccessToken - }); - - const now = Date.now(); - const accessToken = await cli.getAccessToken(); - expect(accessToken).toBeDefined(); - expect(accessToken.token_type).toBe(mockedAccessToken.token_type); - expect(accessToken.access_token).toBe(mockedAccessToken.access_token); - expect(accessToken.expires_in).toBe(mockedAccessToken.expires_in); - expect(accessToken.scope).toBe(mockedAccessToken.scope); - expect(accessToken.created_at).toBeGreaterThanOrEqual(now); + await accessTokenValidator(cli); expect(mockedAxios.request).toBeCalledWith(expect.objectContaining({ url: authUrl, method: "POST", @@ -77,19 +51,7 @@ describe("Get Access Token", ()=>{ ...baseClientParams, grantType: 'PermissaoCustom', }); - mockedAxios.request.mockReset(); - mockedAxios.request.mockResolvedValueOnce({ - data: mockedAccessToken - }); - - const now = Date.now(); - const accessToken = await cli.getAccessToken(); - expect(accessToken).toBeDefined(); - expect(accessToken.token_type).toBe(mockedAccessToken.token_type); - expect(accessToken.access_token).toBe(mockedAccessToken.access_token); - expect(accessToken.expires_in).toBe(mockedAccessToken.expires_in); - expect(accessToken.scope).toBe(mockedAccessToken.scope); - expect(accessToken.created_at).toBeGreaterThanOrEqual(now); + await accessTokenValidator(cli); expect(mockedAxios.request).toBeCalledWith(expect.objectContaining({ url: authUrl, method: "POST", @@ -106,19 +68,7 @@ describe("Get Access Token", ()=>{ ...baseClientParams, authScope: 'EscopoCustom', }); - mockedAxios.request.mockReset(); - mockedAxios.request.mockResolvedValueOnce({ - data: mockedAccessToken - }); - - const now = Date.now(); - const accessToken = await cli.getAccessToken(); - expect(accessToken).toBeDefined(); - expect(accessToken.token_type).toBe(mockedAccessToken.token_type); - expect(accessToken.access_token).toBe(mockedAccessToken.access_token); - expect(accessToken.expires_in).toBe(mockedAccessToken.expires_in); - expect(accessToken.scope).toBe(mockedAccessToken.scope); - expect(accessToken.created_at).toBeGreaterThanOrEqual(now); + await accessTokenValidator(cli); expect(mockedAxios.request).toBeCalledWith(expect.objectContaining({ url: authUrl, method: "POST", @@ -135,19 +85,7 @@ describe("Get Access Token", ()=>{ ...baseClientParams, sendAuthCredentialsOnRequestBody: true, }); - mockedAxios.request.mockReset(); - mockedAxios.request.mockResolvedValueOnce({ - data: mockedAccessToken - }); - - const now = Date.now(); - const accessToken = await cli.getAccessToken(); - expect(accessToken).toBeDefined(); - expect(accessToken.token_type).toBe(mockedAccessToken.token_type); - expect(accessToken.access_token).toBe(mockedAccessToken.access_token); - expect(accessToken.expires_in).toBe(mockedAccessToken.expires_in); - expect(accessToken.scope).toBe(mockedAccessToken.scope); - expect(accessToken.created_at).toBeGreaterThanOrEqual(now); + await accessTokenValidator(cli); expect(mockedAxios.request).toBeCalledWith(expect.objectContaining({ url: authUrl, method: "POST", @@ -160,6 +98,129 @@ describe("Get Access Token", ()=>{ }); }); +describe("Request", ()=>{ + beforeEach(() => { + mockedAxios.request.mockReset(); + mockedAxios.request.mockResolvedValueOnce({ data: mockedAccessToken }); + mockedAxios.request.mockResolvedValueOnce({ data: {"status": "ok"} }); + }); + + it("Get without Params", async ()=>{ + const cli = getOauthClient(); + const resp = await cli.get({ path: '/my-test-url' }); + validateDefaultGetAccessToken(); + expect(mockedAxios.request).toBeCalledWith(expect.objectContaining({ + url: `${apiUrl}/my-test-url`, + method: "GET", + headers: { + Authorization: `Bearer SomeAccessToken`, + 'Content-Type': contentTypeApplicationJson, + }, + data: undefined + })); + expect(resp).toStrictEqual({"status": "ok"}); + }); + + it("Get with Params", async ()=>{ + const cli = getOauthClient(); + const resp = await cli.get({ path: '/my-test-url', params: { id: 1 } }); + validateDefaultGetAccessToken(); + expect(mockedAxios.request).toBeCalledWith(expect.objectContaining({ + url: `${apiUrl}/my-test-url`, + method: "GET", + headers: { + Authorization: `Bearer SomeAccessToken`, + 'Content-Type': contentTypeApplicationJson, + }, + params: { id: 1 }, + data: undefined + })); + expect(resp).toStrictEqual({"status": "ok"}); + }); + + it("Post", async ()=>{ + const cli = getOauthClient(); + const resp = await cli.post({ path: '/my-test-url-post', data: { id: 1, user: 'test' } }); + validateDefaultGetAccessToken(); + expect(mockedAxios.request).toBeCalledWith(expect.objectContaining({ + url: `${apiUrl}/my-test-url-post`, + method: "POST", + headers: { + Authorization: `Bearer SomeAccessToken`, + 'Content-Type': contentTypeApplicationJson, + }, + data: { id: 1, user: 'test' } + })); + expect(resp).toStrictEqual({"status": "ok"}); + }); + + it("Post with different contentType", async ()=>{ + const cli = getOauthClient(); + const resp = await cli.post({ + path: '/my-test-url-post', + data: { id: 1, user: 'test' }, + contentType: ContentType.APPLICATION_X_WWW_FORM_URLENCODED + }); + validateDefaultGetAccessToken(); + expect(mockedAxios.request).toBeCalledWith(expect.objectContaining({ + url: `${apiUrl}/my-test-url-post`, + method: "POST", + headers: { + Authorization: `Bearer SomeAccessToken`, + 'Content-Type': contentTypeApplicationXFormUrlEncoded, + }, + data: { id: 1, user: 'test' } + })); + expect(resp).toStrictEqual({"status": "ok"}); + }); + + it("Post with Different Token Header Name", async ()=>{ + const cli = getOauthClient({ + ...baseClientParams, + tokenHeaderName: "x-token", + }); + const resp = await cli.post({ + path: '/my-test-url-post', + data: { id: 1, user: 'test' }, + contentType: ContentType.APPLICATION_X_WWW_FORM_URLENCODED + }); + validateDefaultGetAccessToken(); + expect(mockedAxios.request).toBeCalledWith(expect.objectContaining({ + url: `${apiUrl}/my-test-url-post`, + method: "POST", + headers: { + 'x-token': `Bearer SomeAccessToken`, + 'Content-Type': contentTypeApplicationXFormUrlEncoded, + }, + data: { id: 1, user: 'test' } + })); + expect(resp).toStrictEqual({"status": "ok"}); + }); +}); + +function validateDefaultGetAccessToken(){ + expect(mockedAxios.request).toBeCalledWith(expect.objectContaining({ + url: authUrl, + method: "POST", + headers: { + Authorization: basicAuth, + 'Content-Type': contentTypeApplicationJson, + }, + data: defaultGrantType, + })); +} + +async function accessTokenValidator(cli: LhispOauthClient){ + const now = Date.now(); + const accessToken = await cli.getAccessToken(); + expect(accessToken).toBeDefined(); + expect(accessToken.token_type).toBe(mockedAccessToken.token_type); + expect(accessToken.access_token).toBe(mockedAccessToken.access_token); + expect(accessToken.expires_in).toBe(mockedAccessToken.expires_in); + expect(accessToken.scope).toBe(mockedAccessToken.scope); + expect(accessToken.created_at).toBeGreaterThanOrEqual(now); +} + function getOauthClient(opt:LhispOauthClientConstructorParams=baseClientParams){ return new LhispOauthClient(opt); } diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml index 4ec6317..8ecdccd 100644 --- a/bitbucket-pipelines.yml +++ b/bitbucket-pipelines.yml @@ -1,33 +1,44 @@ -image: node:14 - +image: node:18-alpine +definitions: + steps: + - step: &build-and-test + name: Build and Test + caches: + - node + script: + - yarn install + - yarn build + artifacts: + - dist/** pipelines: branches: default: - - step: - name: Build and Test - caches: - - node - script: - - yarn install - - yarn build + <<: *build-and-test '{development,realease-no-verify/*}': + - step: *build-and-test - step: - name: Build and Deploy Dev - caches: - - node + name: Prepare Package script: - - yarn install - - yarn build:dev + - apk add git + - cp package.json dist/ + - sed -i s/$BITBUCKET_REPO_SLUG/$BITBUCKET_REPO_SLUG-dev/ dist/package.json + - npm version patch -m "[skip CI] Version %s" + - git push + artifacts: + - dist/** + - step: + name: Publish + deployment: staging + script: + - pipe: atlassian/npm-publish:0.2.0 + variables: + NPM_TOKEN: $NPM_TOKEN + FOLDER: dist master: + - step: *build-and-test - step: - name: Build and Deploy Prod - caches: - - node + name: Prepare Package script: - - yarn install - - yarn build - - mkdir dist/src - - mv dist/*{js,txt} dist/src/ - cp package.json dist/ artifacts: - dist/** diff --git a/package.json b/package.json index 9f48b00..0fd9cf5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lhisp-oauth-client", - "version": "1.0.0", + "version": "1.0.5", "main": "src/index", "types": "src/index.d.ts", "repository": "git@bitbucket.org:leandro_costa/lhisp-oauth-client.git", diff --git a/src/index.js b/src/index.ts similarity index 100% rename from src/index.js rename to src/index.ts diff --git a/src/lhisp-oauth-client.t.ts b/src/lhisp-oauth-client.t.ts index 1cb67b9..d945320 100644 --- a/src/lhisp-oauth-client.t.ts +++ b/src/lhisp-oauth-client.t.ts @@ -23,7 +23,7 @@ export interface LhispOauthClientConstructorParams { export interface ExecutarRequestParams extends AxiosRequestConfig { path: string; - contentType: ContentType, + contentType?: ContentType, } export interface AccessToken { @@ -40,6 +40,6 @@ export enum ContentType { } export const defaultGrantType = 'client_credentials'; -export const defaultAuthContentType = ContentType.APPLICATION_JSON; +export const defaultAuthContentType = ContentType.APPLICATION_X_WWW_FORM_URLENCODED; export const defaultAuthHeaderName = 'Authorization'; export const defaultTokenHeaderName = 'Authorization'; \ No newline at end of file diff --git a/src/lhisp-oauth-client.ts b/src/lhisp-oauth-client.ts index cd546d8..ae26866 100644 --- a/src/lhisp-oauth-client.ts +++ b/src/lhisp-oauth-client.ts @@ -10,7 +10,7 @@ import { LhispOauthClientConstructorParams, } from "./lhisp-oauth-client.t"; -export default class LhispOauthClient { +export class LhispOauthClient { protected authUrl: string; protected apiUrl: string; protected clientId: string;