1
0
mirror of https://github.com/sasjs/adapter.git synced 2026-01-10 13:50:05 +00:00

Compare commits

..

3 Commits

Author SHA1 Message Date
Allan Bowe
c0f78d0c1e fix: updating example.html to use v4 of the adapter 2023-06-22 08:56:32 +01:00
7d826685f7 Merge pull request #813 from sasjs/sasjs-job-execute
fix: issue with parsing json in sasjs job executor
2023-06-15 16:08:08 +02:00
f42f6bca00 fix: issue with parsing json in sasjs job executor 2023-06-14 15:08:11 +02:00
22 changed files with 112 additions and 397 deletions

View File

@@ -22,17 +22,17 @@ jobs:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: npm cache: npm
# - name: Check npm audit - name: Check npm audit
# run: npm audit --production --audit-level=low run: npm audit --production --audit-level=low
- name: Install Dependencies - name: Install Dependencies
run: npm ci run: npm ci
# - name: Check code style - name: Check code style
# run: npm run lint run: npm run lint
# - name: Run unit tests - name: Run unit tests
# run: npm test run: npm test
- name: Build Package - name: Build Package
run: npm run package:lib run: npm run package:lib
@@ -72,27 +72,19 @@ jobs:
npm install -g replace-in-files-cli npm install -g replace-in-files-cli
cd sasjs-tests cd sasjs-tests
replace-in-files --regex='"@sasjs/adapter".*' --replacement='"@sasjs/adapter":"latest",' ./package.json replace-in-files --regex='"@sasjs/adapter".*' --replacement='"@sasjs/adapter":"latest",' ./package.json
npm i --legacy-peer-deps npm i
replace-in-files --regex='"serverUrl".*' --replacement='"serverUrl":"${{ secrets.SASJS_SERVER_URL }}",' ./public/config.json replace-in-files --regex='"serverUrl".*' --replacement='"serverUrl":"${{ secrets.SASJS_SERVER_URL }}",' ./public/config.json
replace-in-files --regex='"userName".*' --replacement='"userName":"${{ secrets.SASJS_USERNAME_DEV }}",' ./public/config.json replace-in-files --regex='"userName".*' --replacement='"userName":"${{ secrets.SASJS_USERNAME }}",' ./public/config.json
replace-in-files --regex='"password".*' --replacement='"password":"${{ secrets.SASJS_PASSWORD_DEV }}",' ./public/config.json replace-in-files --regex='"password".*' --replacement='"password":"${{ secrets.SASJS_PASSWORD }}",' ./public/config.json
replace-in-files --regex='"serverType".*' --replacement='"serverType":"SASJS",' ./public/config.json replace-in-files --regex='"serverType".*' --replacement='"serverType":"SASJS",' ./public/config.json
# npm run update:adapter npm run update:adapter
pm2 start --name sasjs-test npm -- start pm2 start --name sasjs-test npm -- start
cat ./public/config.json
cat ../cypress.json
- name: Sleep for 10 seconds
uses: jakejarvis/wait-action@master
with:
time: '10s'
- name: Run cypress on sasjs - name: Run cypress on sasjs
run: | run: |
ss -lntu
replace-in-files --regex='"sasjsTestsUrl".*' --replacement='"sasjsTestsUrl":"http://localhost:3000",' ./cypress.json replace-in-files --regex='"sasjsTestsUrl".*' --replacement='"sasjsTestsUrl":"http://localhost:3000",' ./cypress.json
replace-in-files --regex='"username".*' --replacement='"username":"${{ secrets.SASJS_USERNAME_DEV }}",' ./cypress.json replace-in-files --regex='"username".*' --replacement='"username":"${{ secrets.SASJS_USERNAME }}",' ./cypress.json
replace-in-files --regex='"password".*' --replacement='"password":"${{ secrets.SASJS_PASSWORD_DEV }}",' ./cypress.json replace-in-files --regex='"password".*' --replacement='"password":"${{ secrets.SASJS_PASSWORD }}",' ./cypress.json
sh ./sasjs-tests/sasjs-cypress-run.sh ${{ secrets.MATRIX_TOKEN }} https://github.com/${{github.repository}}/actions/runs/${{github.run_id}} sh ./sasjs-tests/sasjs-cypress-run.sh ${{ secrets.MATRIX_TOKEN }} https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}
# For some reason if coverage report action is run before other commands, those commands can't access the directories and files on which they depend on # For some reason if coverage report action is run before other commands, those commands can't access the directories and files on which they depend on

View File

@@ -5,9 +5,6 @@ const testingFinishTimeout = Cypress.env('testingFinishTimeout')
context('sasjs-tests', function () { context('sasjs-tests', function () {
this.beforeAll(() => { this.beforeAll(() => {
cy.task('log', 'beforeAll')
cy.task('log', `sasjsTestsUrl: ${sasjsTestsUrl}`)
cy.visit(sasjsTestsUrl) cy.visit(sasjsTestsUrl)
}) })
@@ -16,66 +13,35 @@ context('sasjs-tests', function () {
}) })
it('Should have all tests successfull', (done) => { it('Should have all tests successfull', (done) => {
cy.task('log', `Should have all tests successfull`)
cy.get('body').then(($body) => { cy.get('body').then(($body) => {
cy.task('log', `22`)
cy.wait(1000).then(() => { cy.wait(1000).then(() => {
const startButton = $body.find( const startButton = $body.find(
'.ui.massive.icon.primary.left.labeled.button' '.ui.massive.icon.primary.left.labeled.button'
)[0] )[0]
// ui massive icon primary left labeled button
cy.task('log', `startButton: ${startButton}`)
if ( if (
!startButton || !startButton ||
(startButton && !Cypress.dom.isVisible(startButton)) (startButton && !Cypress.dom.isVisible(startButton))
) { ) {
cy.task('log', `34`)
cy.task('log', `username: ${username}`)
cy.task('log', `password: ${password}`)
const userNameInput = cy.get('input[placeholder="User Name"]')
const passwordInput = cy.get('input[placeholder="Password"]')
cy.task('log', `userNameInput: ${userNameInput}`)
cy.task('log', `passwordInput: ${passwordInput}`)
cy.get('input[placeholder="User Name"]').type(username) cy.get('input[placeholder="User Name"]').type(username)
cy.get('input[placeholder="Password"]').type(password) cy.get('input[placeholder="Password"]').type(password)
const submitBtn = cy.get('.submit-button')
cy.task('log', `submitBtn: ${submitBtn}`)
cy.get('.submit-button').click() cy.get('.submit-button').click()
} }
cy.get('input[placeholder="User Name"]', { timeout: 40000 }) cy.get('input[placeholder="User Name"]', { timeout: 40000 })
.should('not.exist') .should('not.exist')
.then(() => { .then(() => {
cy.task('log', `46`)
cy.get('.ui.massive.icon.primary.left.labeled.button') cy.get('.ui.massive.icon.primary.left.labeled.button')
.click() .click()
.then(() => { .then(() => {
cy.task('log', `50`)
const loadingButton = $body.find(
'.ui.massive.loading.primary.button'
)[0]
cy.task('log', `loadingButton: ${loadingButton}`)
cy.get('.ui.massive.loading.primary.button', { cy.get('.ui.massive.loading.primary.button', {
timeout: testingFinishTimeout timeout: testingFinishTimeout
}) })
.should('not.exist') .should('not.exist')
.then(() => { .then(() => {
cy.task('log', `56`)
cy.get('span.icon.failed') cy.get('span.icon.failed')
.should('not.exist') .should('not.exist')
.then(() => { .then(() => {
cy.task('log', `60`)
done() done()
}) })
}) })
@@ -85,46 +51,46 @@ context('sasjs-tests', function () {
}) })
}) })
// it('Should have all tests successfull with debug on', (done) => { it('Should have all tests successfull with debug on', (done) => {
// cy.get('body').then(($body) => { cy.get('body').then(($body) => {
// cy.wait(1000).then(() => { cy.wait(1000).then(() => {
// const startButton = $body.find( const startButton = $body.find(
// '.ui.massive.icon.primary.left.labeled.button' '.ui.massive.icon.primary.left.labeled.button'
// )[0] )[0]
// if ( if (
// !startButton || !startButton ||
// (startButton && !Cypress.dom.isVisible(startButton)) (startButton && !Cypress.dom.isVisible(startButton))
// ) { ) {
// cy.get('input[placeholder="User Name"]').type(username) cy.get('input[placeholder="User Name"]').type(username)
// cy.get('input[placeholder="Password"]').type(password) cy.get('input[placeholder="Password"]').type(password)
// cy.get('.submit-button').click() cy.get('.submit-button').click()
// } }
// cy.get('.ui.fitted.toggle.checkbox label') cy.get('.ui.fitted.toggle.checkbox label')
// .click() .click()
// .then(() => { .then(() => {
// cy.get('input[placeholder="User Name"]', { timeout: 40000 }) cy.get('input[placeholder="User Name"]', { timeout: 40000 })
// .should('not.exist') .should('not.exist')
// .then(() => { .then(() => {
// cy.get('.ui.massive.icon.primary.left.labeled.button') cy.get('.ui.massive.icon.primary.left.labeled.button')
// .click() .click()
// .then(() => { .then(() => {
// cy.get('.ui.massive.loading.primary.button', { cy.get('.ui.massive.loading.primary.button', {
// timeout: testingFinishTimeout timeout: testingFinishTimeout
// }) })
// .should('not.exist') .should('not.exist')
// .then(() => { .then(() => {
// cy.get('span.icon.failed') cy.get('span.icon.failed')
// .should('not.exist') .should('not.exist')
// .then(() => { .then(() => {
// done() done()
// }) })
// }) })
// }) })
// }) })
// }) })
// }) })
// }) })
// }) })
}) })

View File

@@ -39,11 +39,4 @@ module.exports = (on, config) => {
return launchOptions return launchOptions
} }
}) })
on('task', {
log(message) {
console.log(message)
return null
}
})
} }

View File

@@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<script src="https://cdn.jsdelivr.net/combine/npm/chart.js@2.9.3,npm/jquery@3.5.1,npm/@sasjs/adapter@1"></script> <script src="https://cdn.jsdelivr.net/combine/npm/chart.js@2.9.3,npm/jquery@3.5.1,npm/@sasjs/adapter@4"></script>
<script> <script>
var sasJs = new SASjs.default({ var sasJs = new SASjs.default({
appLoc: "/Public/app/readme" appLoc: "/Public/app/readme"

View File

@@ -8,7 +8,7 @@
"name": "@sasjs/tests", "name": "@sasjs/tests",
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@sasjs/adapter": "4.3.5", "@sasjs/adapter": "file:../build/sasjs-adapter-5.0.0.tgz",
"@sasjs/test-framework": "1.5.7", "@sasjs/test-framework": "1.5.7",
"@types/jest": "^26.0.20", "@types/jest": "^26.0.20",
"@types/node": "^14.14.41", "@types/node": "^14.14.41",
@@ -3113,10 +3113,11 @@
"integrity": "sha512-WiBSI6JBIhC6LRIsB2Kwh8DsGTlbBU+mLRxJmAe3LjHTdkDpwIbEOZgoXBbZilk/vlfjK8i6nKRAvIRn1XaIMw==" "integrity": "sha512-WiBSI6JBIhC6LRIsB2Kwh8DsGTlbBU+mLRxJmAe3LjHTdkDpwIbEOZgoXBbZilk/vlfjK8i6nKRAvIRn1XaIMw=="
}, },
"node_modules/@sasjs/adapter": { "node_modules/@sasjs/adapter": {
"version": "4.3.5", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/@sasjs/adapter/-/adapter-4.3.5.tgz", "resolved": "file:../build/sasjs-adapter-5.0.0.tgz",
"integrity": "sha512-ihVcmGQYPIZ3WTZOQd8xe/RDvtqK9lQmLx7hujmKeaN0RM/LsenYWIpM0nXKdw/2KruoghxMBNFLzpJUxJT4OA==", "integrity": "sha512-BK+ZrvPeOqjCmHVLm3VtiQ/ATOTqjp+TibQixuG4DbljonBxZS/DnRZ0a1hOQUpCUZVKDRVtCNQ3ROtKUqxxrA==",
"hasInstallScript": true, "hasInstallScript": true,
"license": "ISC",
"dependencies": { "dependencies": {
"@sasjs/utils": "2.52.0", "@sasjs/utils": "2.52.0",
"axios": "0.27.2", "axios": "0.27.2",
@@ -20164,9 +20165,8 @@
"integrity": "sha512-WiBSI6JBIhC6LRIsB2Kwh8DsGTlbBU+mLRxJmAe3LjHTdkDpwIbEOZgoXBbZilk/vlfjK8i6nKRAvIRn1XaIMw==" "integrity": "sha512-WiBSI6JBIhC6LRIsB2Kwh8DsGTlbBU+mLRxJmAe3LjHTdkDpwIbEOZgoXBbZilk/vlfjK8i6nKRAvIRn1XaIMw=="
}, },
"@sasjs/adapter": { "@sasjs/adapter": {
"version": "4.3.5", "version": "file:../build/sasjs-adapter-5.0.0.tgz",
"resolved": "https://registry.npmjs.org/@sasjs/adapter/-/adapter-4.3.5.tgz", "integrity": "sha512-BK+ZrvPeOqjCmHVLm3VtiQ/ATOTqjp+TibQixuG4DbljonBxZS/DnRZ0a1hOQUpCUZVKDRVtCNQ3ROtKUqxxrA==",
"integrity": "sha512-ihVcmGQYPIZ3WTZOQd8xe/RDvtqK9lQmLx7hujmKeaN0RM/LsenYWIpM0nXKdw/2KruoghxMBNFLzpJUxJT4OA==",
"requires": { "requires": {
"@sasjs/utils": "2.52.0", "@sasjs/utils": "2.52.0",
"axios": "0.27.2", "axios": "0.27.2",

View File

@@ -4,7 +4,7 @@
"homepage": ".", "homepage": ".",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@sasjs/adapter": "4.3.5", "@sasjs/adapter": "file:../build/sasjs-adapter-5.0.0.tgz",
"@sasjs/test-framework": "1.5.7", "@sasjs/test-framework": "1.5.7",
"@types/jest": "^26.0.20", "@types/jest": "^26.0.20",
"@types/node": "^14.14.41", "@types/node": "^14.14.41",

View File

@@ -2,7 +2,7 @@
"userName": "", "userName": "",
"password": "", "password": "",
"sasJsConfig": { "sasJsConfig": {
"serverUrl": "https://sas9.4gl.io", "serverUrl": "",
"appLoc": "/Public/app/adapter-tests/services", "appLoc": "/Public/app/adapter-tests/services",
"serverType": "SASJS", "serverType": "SASJS",
"debug": false, "debug": false,

View File

@@ -1,9 +1,7 @@
{ {
"$schema": "https://cli.sasjs.io/sasjsconfig-schema.json", "$schema": "https://cli.sasjs.io/sasjsconfig-schema.json",
"serviceConfig": { "serviceConfig": {
"serviceFolders": [ "serviceFolders": ["sasjs/common"]
"sasjs/common"
]
}, },
"defaultTarget": "4gl", "defaultTarget": "4gl",
"targets": [ "targets": [

View File

@@ -11,7 +11,7 @@ const Login = (): ReactElement<{}> => {
const handleSubmit = useCallback( const handleSubmit = useCallback(
(e: any) => { (e: any) => {
e.preventDefault() e.preventDefault()
appContext.adapter.logIn(username, password).then((res: any) => { appContext.adapter.logIn(username, password).then((res) => {
appContext.setIsLoggedIn(res.isLoggedIn) appContext.setIsLoggedIn(res.isLoggedIn)
}) })
}, },

View File

@@ -1,7 +1,5 @@
import { prefixMessage } from '@sasjs/utils/error' import { prefixMessage } from '@sasjs/utils/error'
import { RequestClient } from '../request/RequestClient' import { RequestClient } from '../request/RequestClient'
import { getTokenRequestErrorPrefix } from './getTokenRequestErrorPrefix'
import { ServerType } from '@sasjs/utils'
/** /**
* Exchanges the auth code for an access token for the given client. * Exchanges the auth code for an access token for the given client.
@@ -33,16 +31,6 @@ export async function getAccessTokenForSasjs(
} }
}) })
.catch((err) => { .catch((err) => {
throw prefixMessage( throw prefixMessage(err, 'Error while getting access token. ')
err,
getTokenRequestErrorPrefix(
'fetching access token',
'getAccessTokenForSasjs',
ServerType.Sasjs,
url,
data,
clientId
)
)
}) })
} }

View File

@@ -1,13 +1,11 @@
import { SasAuthResponse, ServerType } from '@sasjs/utils/types' import { SasAuthResponse } from '@sasjs/utils/types'
import { prefixMessage } from '@sasjs/utils/error' import { prefixMessage } from '@sasjs/utils/error'
import { RequestClient } from '../request/RequestClient' import { RequestClient } from '../request/RequestClient'
import { CertificateError } from '../types/errors' import { CertificateError } from '../types/errors'
import { getTokenRequestErrorPrefix } from './getTokenRequestErrorPrefix'
// TODO: update func docs
/** /**
* Exchange the auth code for access / refresh tokens for the given client / secret pair. * Exchanges the auth code for an access token for the given client.
* @param requestClient - the pre-configured HTTP request client. * @param requestClient - the pre-configured HTTP request client
* @param clientId - the client ID to authenticate with. * @param clientId - the client ID to authenticate with.
* @param clientSecret - the client secret to authenticate with. * @param clientSecret - the client secret to authenticate with.
* @param authCode - the auth code received from the server. * @param authCode - the auth code received from the server.
@@ -18,43 +16,29 @@ export async function getAccessTokenForViya(
clientSecret: string, clientSecret: string,
authCode: string authCode: string
): Promise<SasAuthResponse> { ): Promise<SasAuthResponse> {
const url = '/SASLogon/oauth/token'
let token let token
if (typeof Buffer === 'undefined') { if (typeof Buffer === 'undefined') {
token = btoa(clientId + ':' + clientSecret) token = btoa(clientId + ':' + clientSecret)
} else { } else {
token = Buffer.from(clientId + ':' + clientSecret).toString('base64') token = Buffer.from(clientId + ':' + clientSecret).toString('base64')
} }
const url = '/SASLogon/oauth/token'
const headers = { const headers = {
Authorization: 'Basic ' + token, Authorization: 'Basic ' + token,
Accept: 'application/json' Accept: 'application/json'
} }
const dataJson = {
const data = new URLSearchParams({
grant_type: 'authorization_code', grant_type: 'authorization_code',
code: authCode code: authCode
} })
const data = new URLSearchParams(dataJson)
const authResponse = await requestClient const authResponse = await requestClient
.post(url, data, undefined, 'application/x-www-form-urlencoded', headers) .post(url, data, undefined, 'application/x-www-form-urlencoded', headers)
.then((res) => res.result as SasAuthResponse) .then((res) => res.result as SasAuthResponse)
.catch((err) => { .catch((err) => {
if (err instanceof CertificateError) throw err if (err instanceof CertificateError) throw err
throw prefixMessage( throw prefixMessage(err, 'Error while getting access token. ')
err,
getTokenRequestErrorPrefix(
'fetching access token',
'getAccessTokenForViya',
ServerType.SasViya,
url,
dataJson,
headers,
clientId,
clientSecret
)
)
}) })
return authResponse return authResponse

View File

@@ -1,88 +0,0 @@
import { ServerType } from '@sasjs/utils/types'
type Server = ServerType.SasViya | ServerType.Sasjs
type Operation = 'fetching access token' | 'refreshing tokens'
const getServerName = (server: Server) =>
server === ServerType.SasViya ? 'Viya' : 'Sasjs'
const getResponseTitle = (server: Server) =>
`Response from ${getServerName(server)} is below.`
/**
* Forms error prefix for requests related to token operations.
* @param operation - string describing operation ('fetching access token' or 'refreshing tokens').
* @param funcName - name of the function sent the request.
* @param server - server type (SASVIYA or SASJS).
* @param url - endpoint used to send the request.
* @param data - request payload.
* @param headers - request headers.
* @param clientId - client ID to authenticate with.
* @param clientSecret - client secret to authenticate with.
* @returns - string containing request information. Example:
* Error while fetching access token from /SASLogon/oauth/token
* Thrown by the @sasjs/adapter getAccessTokenForViya function.
* Payload:
* {
* "grant_type": "authorization_code",
* "code": "example_code"
* }
* Headers:
* {
* "Authorization": "Basic NEdMQXBwOjRHTEFwcDE=",
* "Accept": "application/json"
* }
* ClientId: exampleClientId
* ClientSecret: exampleClientSecret
*
* Response from Viya is below.
* Auth error: {
* "error": "invalid_token",
* "error_description": "No scopes were granted"
* }
*/
export const getTokenRequestErrorPrefix = (
operation: Operation,
funcName: string,
server: Server,
url: string,
data?: {},
headers?: {},
clientId?: string,
clientSecret?: string
) => {
const stringify = (obj: {}) => JSON.stringify(obj, null, 2)
const lines = [
`Error while ${operation} from ${url}`,
`Thrown by the @sasjs/adapter ${funcName} function.`
]
if (data) {
lines.push('Payload:')
lines.push(stringify(data))
}
if (headers) {
lines.push('Headers:')
lines.push(stringify(headers))
}
if (clientId) lines.push(`ClientId: ${clientId}`)
if (clientSecret) lines.push(`ClientSecret: ${clientSecret}`)
lines.push('')
lines.push(`${getResponseTitle(server)}`)
lines.push('')
return lines.join(`\n`)
}
/**
* Parse error prefix to get response payload.
* @param prefix - error prefix generated by getTokenRequestErrorPrefix function.
* @param server - server type (SASVIYA or SASJS).
* @returns - response payload.
*/
export const getTokenRequestErrorPrefixResponse = (
prefix: string,
server: ServerType.SasViya | ServerType.Sasjs
) => prefix.split(`${getResponseTitle(server)}\n`).pop() as string

View File

@@ -22,7 +22,6 @@ export async function getTokens(
): Promise<AuthConfig> { ): Promise<AuthConfig> {
const logger = process.logger || console const logger = process.logger || console
let { access_token, refresh_token, client, secret } = authConfig let { access_token, refresh_token, client, secret } = authConfig
if ( if (
isAccessTokenExpiring(access_token) || isAccessTokenExpiring(access_token) ||
isRefreshTokenExpiring(refresh_token) isRefreshTokenExpiring(refresh_token)
@@ -30,7 +29,6 @@ export async function getTokens(
if (hasTokenExpired(refresh_token)) { if (hasTokenExpired(refresh_token)) {
const error = const error =
'Unable to obtain new access token. Your refresh token has expired.' 'Unable to obtain new access token. Your refresh token has expired.'
logger.error(error) logger.error(error)
throw new Error(error) throw new Error(error)
@@ -49,6 +47,5 @@ export async function getTokens(
: await refreshTokensForSasjs(requestClient, refresh_token) : await refreshTokensForSasjs(requestClient, refresh_token)
;({ access_token, refresh_token } = tokens) ;({ access_token, refresh_token } = tokens)
} }
return { access_token, refresh_token, client, secret } return { access_token, refresh_token, client, secret }
} }

View File

@@ -1,7 +1,5 @@
import { prefixMessage } from '@sasjs/utils/error' import { prefixMessage } from '@sasjs/utils/error'
import { RequestClient } from '../request/RequestClient' import { RequestClient } from '../request/RequestClient'
import { getTokenRequestErrorPrefix } from './getTokenRequestErrorPrefix'
import { ServerType } from '@sasjs/utils'
/** /**
* Exchanges the refresh token for an access token for the given client. * Exchanges the refresh token for an access token for the given client.
@@ -30,15 +28,7 @@ export async function refreshTokensForSasjs(
} }
}) })
.catch((err) => { .catch((err) => {
throw prefixMessage( throw prefixMessage(err, 'Error while refreshing tokens: ')
err,
getTokenRequestErrorPrefix(
'refreshing tokens',
'refreshTokensForSasjs',
ServerType.Sasjs,
url
)
)
}) })
return authResponse return authResponse

View File

@@ -1,9 +1,8 @@
import { SasAuthResponse, ServerType } from '@sasjs/utils/types' import { SasAuthResponse } from '@sasjs/utils/types'
import { prefixMessage } from '@sasjs/utils/error' import { prefixMessage } from '@sasjs/utils/error'
import * as NodeFormData from 'form-data' import * as NodeFormData from 'form-data'
import { RequestClient } from '../request/RequestClient' import { RequestClient } from '../request/RequestClient'
import { isNode } from '../utils' import { isNode } from '../utils'
import { getTokenRequestErrorPrefix } from './getTokenRequestErrorPrefix'
/** /**
* Exchanges the refresh token for an access token for the given client. * Exchanges the refresh token for an access token for the given client.
@@ -47,19 +46,7 @@ export async function refreshTokensForViya(
) )
.then((res) => res.result) .then((res) => res.result)
.catch((err) => { .catch((err) => {
throw prefixMessage( throw prefixMessage(err, 'Error while refreshing tokens: ')
err,
getTokenRequestErrorPrefix(
'refreshing tokens',
'refreshTokensForViya',
ServerType.SasViya,
url,
formData,
headers,
clientId,
clientSecret
)
)
}) })
return authResponse return authResponse

View File

@@ -55,7 +55,7 @@ describe('getAccessTokenForSasjs', () => {
authConfig.refresh_token authConfig.refresh_token
).catch((e: any) => e) ).catch((e: any) => e)
expect(error).toContain('Error while fetching access token') expect(error).toContain('Error while getting access token')
}) })
}) })

View File

@@ -66,7 +66,7 @@ describe('getAccessTokenForViya', () => {
authConfig.refresh_token authConfig.refresh_token
).catch((e: any) => e) ).catch((e: any) => e)
expect(error).toContain('Error while fetching access token') expect(error).toContain('Error while getting access token')
}) })
}) })

View File

@@ -1,81 +0,0 @@
import { ServerType } from '@sasjs/utils/types'
import { getTokenRequestErrorPrefix } from '../getTokenRequestErrorPrefix'
describe('getTokenRequestErrorPrefix', () => {
it('should return error prefix', () => {
// INFO: Viya with only required attributes
let operation: 'fetching access token' = 'fetching access token'
const funcName = 'testFunc'
const url = '/SASjsApi/auth/token'
let expectedPrefix = `Error while ${operation} from ${url}
Thrown by the @sasjs/adapter ${funcName} function.
Response from Viya is below.
`
expect(
getTokenRequestErrorPrefix(operation, funcName, ServerType.SasViya, url)
).toEqual(expectedPrefix)
// INFO: Sasjs with data and headers
const data = {
grant_type: 'authorization_code',
code: 'testCode'
}
const headers = {
Authorization: 'Basic test=',
Accept: 'application/json'
}
expectedPrefix = `Error while ${operation} from ${url}
Thrown by the @sasjs/adapter ${funcName} function.
Payload:
${JSON.stringify(data, null, 2)}
Headers:
${JSON.stringify(headers, null, 2)}
Response from Sasjs is below.
`
expect(
getTokenRequestErrorPrefix(
operation,
funcName,
ServerType.Sasjs,
url,
data,
headers
)
).toEqual(expectedPrefix)
// INFO: Viya with all attributes
const clientId = 'testId'
const clientSecret = 'testSecret'
expectedPrefix = `Error while ${operation} from ${url}
Thrown by the @sasjs/adapter ${funcName} function.
Payload:
${JSON.stringify(data, null, 2)}
Headers:
${JSON.stringify(headers, null, 2)}
ClientId: ${clientId}
ClientSecret: ${clientSecret}
Response from Viya is below.
`
expect(
getTokenRequestErrorPrefix(
operation,
funcName,
ServerType.SasViya,
url,
data,
headers,
clientId,
clientSecret
)
).toEqual(expectedPrefix)
})
})

View File

@@ -1,8 +1,6 @@
import { ServerType } from '@sasjs/utils'
import { generateToken, mockAuthResponse } from './mockResponses' import { generateToken, mockAuthResponse } from './mockResponses'
import { RequestClient } from '../../request/RequestClient' import { RequestClient } from '../../request/RequestClient'
import { refreshTokensForSasjs } from '../refreshTokensForSasjs' import { refreshTokensForSasjs } from '../refreshTokensForSasjs'
import { getTokenRequestErrorPrefixResponse } from '../getTokenRequestErrorPrefix'
const requestClient = new (<jest.Mock<RequestClient>>RequestClient)() const requestClient = new (<jest.Mock<RequestClient>>RequestClient)()
@@ -40,9 +38,9 @@ describe('refreshTokensForSasjs', () => {
const error = await refreshTokensForSasjs( const error = await refreshTokensForSasjs(
requestClient, requestClient,
refresh_token refresh_token
).catch((e: any) => getTokenRequestErrorPrefixResponse(e, ServerType.Sasjs)) ).catch((e: any) => e)
expect(error).toEqual(tokenError) expect(error).toEqual(`Error while refreshing tokens: ${tokenError}`)
}) })
}) })

View File

@@ -1,10 +1,9 @@
import { AuthConfig, ServerType } from '@sasjs/utils' import { AuthConfig } from '@sasjs/utils'
import * as NodeFormData from 'form-data' import * as NodeFormData from 'form-data'
import { generateToken, mockAuthResponse } from './mockResponses' import { generateToken, mockAuthResponse } from './mockResponses'
import { RequestClient } from '../../request/RequestClient' import { RequestClient } from '../../request/RequestClient'
import { refreshTokensForViya } from '../refreshTokensForViya' import { refreshTokensForViya } from '../refreshTokensForViya'
import * as IsNodeModule from '../../utils/isNode' import * as IsNodeModule from '../../utils/isNode'
import { getTokenRequestErrorPrefixResponse } from '../getTokenRequestErrorPrefix'
const requestClient = new (<jest.Mock<RequestClient>>RequestClient)() const requestClient = new (<jest.Mock<RequestClient>>RequestClient)()
@@ -68,11 +67,9 @@ describe('refreshTokensForViya', () => {
authConfig.client, authConfig.client,
authConfig.secret, authConfig.secret,
authConfig.refresh_token authConfig.refresh_token
).catch((e: any) => ).catch((e: any) => e)
getTokenRequestErrorPrefixResponse(e, ServerType.SasViya)
)
expect(error).toEqual(tokenError) expect(error).toEqual(`Error while refreshing tokens: ${tokenError}`)
}) })
it('should throw an error if environment is not Node', async () => { it('should throw an error if environment is not Node', async () => {

View File

@@ -93,8 +93,10 @@ export class SasjsJobExecutor extends BaseJobExecutor {
) )
} }
const { result } = res.result const { result } = res
if (result && result.trim()) res.result = getValidJson(result)
if (result && typeof result === 'string' && result.trim())
res.result = getValidJson(result)
this.requestClient!.appendRequest(res, sasJob, config.debug) this.requestClient!.appendRequest(res, sasJob, config.debug)

View File

@@ -11,8 +11,8 @@ import {
NotFoundError, NotFoundError,
InternalServerError InternalServerError
} from '../types/errors' } from '../types/errors'
import { prefixMessage } from '@sasjs/utils/error'
import { RequestClient } from '../request/RequestClient' import { RequestClient } from '../request/RequestClient'
import { getTokenRequestErrorPrefixResponse } from '../auth/getTokenRequestErrorPrefix'
const axiosActual = jest.requireActual('axios') const axiosActual = jest.requireActual('axios')
@@ -66,18 +66,14 @@ describe('RequestClient', () => {
}) })
it('should response the POST method with Unauthorized', async () => { it('should response the POST method with Unauthorized', async () => {
const expectedError = new LoginRequiredError({ await expect(
error: 'unauthorized', adapter.getAccessToken('clientId', 'clientSecret', 'incorrect')
error_description: 'Bad credentials' ).rejects.toEqual(
}) prefixMessage(
new LoginRequiredError(incorrectAuthCodeErr),
const rejectionErrorMessage = await adapter 'Error while getting access token. '
.getAccessToken('clientId', 'clientSecret', 'incorrect')
.catch((err) =>
getTokenRequestErrorPrefixResponse(err.message, ServerType.SasViya)
) )
)
expect(rejectionErrorMessage).toEqual(expectedError.message)
}) })
describe('handleError', () => { describe('handleError', () => {
@@ -213,15 +209,15 @@ describe('RequestClient - Self Signed Server', () => {
serverType: ServerType.SasViya serverType: ServerType.SasViya
}) })
const expectedError = 'self signed certificate' await expect(
adapterWithoutCertificate.getAccessToken(
const rejectionErrorMessage = await adapterWithoutCertificate 'clientId',
.getAccessToken('clientId', 'clientSecret', 'authCode') 'clientSecret',
.catch((err) => 'authCode'
getTokenRequestErrorPrefixResponse(err.message, ServerType.SasViya)
) )
).rejects.toThrow(
expect(rejectionErrorMessage).toEqual(expectedError) `Error while getting access token. ${ERROR_MESSAGES.selfSigned}`
)
}) })
it('should response the POST method using insecure flag', async () => { it('should response the POST method using insecure flag', async () => {
@@ -251,18 +247,14 @@ describe('RequestClient - Self Signed Server', () => {
}) })
it('should response the POST method with Unauthorized', async () => { it('should response the POST method with Unauthorized', async () => {
const expectedError = new LoginRequiredError({ await expect(
error: 'unauthorized', adapter.getAccessToken('clientId', 'clientSecret', 'incorrect')
error_description: 'Bad credentials' ).rejects.toEqual(
}) prefixMessage(
new LoginRequiredError(incorrectAuthCodeErr),
const rejectionErrorMessage = await adapter 'Error while getting access token. '
.getAccessToken('clientId', 'clientSecret', 'incorrect')
.catch((err) =>
getTokenRequestErrorPrefixResponse(err.message, ServerType.SasViya)
) )
)
expect(rejectionErrorMessage).toEqual(expectedError.message)
}) })
}) })