mirror of
https://github.com/sasjs/adapter.git
synced 2026-01-10 05:40:06 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c0f78d0c1e | ||
| 7d826685f7 | |||
| f42f6bca00 |
32
.github/workflows/build.yml
vendored
32
.github/workflows/build.yml
vendored
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
// })
|
})
|
||||||
// })
|
})
|
||||||
// })
|
})
|
||||||
// })
|
})
|
||||||
// })
|
})
|
||||||
// })
|
})
|
||||||
// })
|
})
|
||||||
// })
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -39,11 +39,4 @@ module.exports = (on, config) => {
|
|||||||
return launchOptions
|
return launchOptions
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
on('task', {
|
|
||||||
log(message) {
|
|
||||||
console.log(message)
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
14
sasjs-tests/package-lock.json
generated
14
sasjs-tests/package-lock.json
generated
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
@@ -45,4 +45,4 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"node-sass": "7.0.3"
|
"node-sass": "7.0.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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": [
|
||||||
@@ -28,4 +26,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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
|
|
||||||
)
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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 }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -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')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -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}`)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -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 () => {
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user