Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions e2e/.env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
CONSOLEAPI_API_KEY=
CONSOLEAPI_ACCESS_TOKEN=
CONSOLEAPI_IMS_ORG_ID=
CONSOLEAPI_ENV=
CONSOLE_API_API_KEY=
CONSOLE_API_ACCESS_TOKEN=
CONSOLE_API_IMS_ORG_ID=
CONSOLE_API_ENV=
8 changes: 4 additions & 4 deletions e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

To run the e2e test you'll need these env variables set (copy `.env.example` to `.env`):

1. `CONSOLEAPI_API_KEY` (this is the same IMS client id used by the cli)
2. `CONSOLEAPI_ACCESS_TOKEN` (this is the access token retrieved by an `aio login`)
3. `CONSOLEAPI_IMS_ORG_ID` (get this from the App Builder project's `.aio` file)
4. `CONSOLEAPI_ENV` (`prod` (default) or `stage`)
1. `CONSOLE_API_API_KEY` (this is the same IMS client id used by the cli)
2. `CONSOLE_API_ACCESS_TOKEN` (this is the access token retrieved by an `aio login`)
3. `CONSOLE_API_IMS_ORG_ID` (get this from the App Builder project's `.aio` file)
4. `CONSOLE_API_ENV` (`prod` (default) or `stage`)

## Run

Expand Down
393 changes: 393 additions & 0 deletions e2e/e2e.credentials.js

Large diffs are not rendered by default.

846 changes: 204 additions & 642 deletions e2e/e2e.js

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions e2e/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
module.exports = {
testEnvironment: 'node',
globalSetup: './jest.globalSetup.js',
setupFilesAfterEnv: [
'../test/jest/jest.setup.js'
'./jest.setup.js'
],
testRegex: './e2e/e2e.js'
testRegex: 'e2e/e2e.*\\.js$'
}
24 changes: 24 additions & 0 deletions e2e/jest.globalSetup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
Copyright 2026 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License.
*/

const path = require('path')

// Runs once before any test suite. Validates that the required environment
// variables are present so tests fail fast with a clear error message.
module.exports = async () => {
require('dotenv').config({ path: path.join(__dirname, '.env') })

const missingEnvVars = ['CONSOLE_API_API_KEY', 'CONSOLE_API_ACCESS_TOKEN', 'CONSOLE_API_IMS_ORG_ID']
.filter(v => !process.env[v]?.trim())
if (missingEnvVars.length > 0) {
throw new Error(`Missing required environment variables: ${missingEnvVars.join(', ')}`)
}
}
93 changes: 93 additions & 0 deletions e2e/jest.setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
Copyright 2023 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License.
*/

// Runs in each test file's context (setupFilesAfterEnv).
// Provides shared globals: sdkClient, orgId, apiKey, accessToken, imsOrgId, env, findSDKCode.

const sdk = require('../src')
const path = require('path')
const services = require('../services.json')

require('dotenv').config({ path: path.join(__dirname, '.env') })

jest.setTimeout(120000)

const {
CONSOLE_API_API_KEY: apiKey,
CONSOLE_API_ACCESS_TOKEN: accessToken,
CONSOLE_API_IMS_ORG_ID: imsOrgId,
CONSOLE_API_ENV: env = 'prod'
} = process.env

Object.assign(global, { apiKey, accessToken, imsOrgId, env })

/**
* Finds the SDK code for a given SDK name from the services registry.
*
* @param {string} sdkName - The display name of the SDK service to look up.
* @returns {string|null} The SDK code if found, or null if no matching service exists.
*/
global.findSDKCode = function findSDKCode (sdkName) {
const service = services.find(service => service.name === sdkName)
return service ? service.code : null
}

/**
* Asserts that a response represents a successful HTTP 200 OK result.
*
* @param {object} res - The response object returned by the SDK client.
* @param {string} expectedBodyType - The expected typeof value for `res.body` (e.g. `'object'`, `'string'`).
*/
/* eslint-disable jest/no-standalone-expect */
global.expectOkResponse = function expectOkResponse (res, expectedBodyType) {
expect(res.ok).toBe(true)
expect(res.status).toBe(200)
expect(res.statusText).toBe('OK')
expect(typeof res.body).toBe(expectedBodyType)
}
/* eslint-enable jest/no-standalone-expect */

/**
* Asserts that a response represents a successful HTTP 201 Created result.
*
* @param {object} res - The response object returned by the SDK client.
* @param {string} expectedBodyType - The expected typeof value for `res.body` (e.g. `'object'`, `'string'`).
*/
/* eslint-disable jest/no-standalone-expect */
global.expectCreatedResponse = function expectCreatedResponse (res, expectedBodyType) {
expect(res.ok).toBe(true)
expect(res.status).toBe(201)
expect(res.statusText).toBe('Created')
expect(typeof res.body).toBe(expectedBodyType)
}
/* eslint-enable jest/no-standalone-expect */

/**
* Initializes the SDK client and resolves the organization ID for the configured IMS org.
* Runs once before all tests via `beforeAll`.
*
* @returns {Promise<void>}
*/
async function init () {
global.sdkClient = await sdk.init(accessToken, apiKey, env)
console.log(`Initialized SDK client with env ${env} and API key ${apiKey}`)
Comment thread
shazron marked this conversation as resolved.

const res = await global.sdkClient.getOrganizations()
const org = res.body.find(item => item.code === imsOrgId)
Comment thread
shazron marked this conversation as resolved.
if (org) {
global.orgId = org.id
console.log(`Found organization with ID ${global.orgId}`)
} else {
throw new Error(`Organization with IMS org ID ${imsOrgId} not found in response from getOrganizations`)
}
}

beforeAll(init)
2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
"@adobe/aio-lib-core-logging": "^3",
"@adobe/aio-lib-core-networking": "^5.0.2",
"@adobe/aio-lib-env": "^3",
"axios": "^1.7.9",
"form-data": "^4.0.1",
"swagger-client": "^3.31.0"
},
"devDependencies": {
Expand Down
23 changes: 11 additions & 12 deletions src/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ governing permissions and limitations under the License.
*/
const loggerNamespace = '@adobe/aio-lib-console'
const logger = require('@adobe/aio-lib-core-logging')(loggerNamespace, { provider: 'debug', level: process.env.LOG_LEVEL || 'debug' })
const axios = require('axios')
const FormData = require('form-data')

/**
* Reduce an Error to a string
Expand Down Expand Up @@ -118,33 +116,34 @@ function responseInterceptor (res) {
}

/**
* Use axios lib to directly call console API to create credential
* Use fetch to directly call console API to create credential
*
* @param {string} url URL string
* @param {string} accessToken Token to call the API
* @param {string} apiKey Api key
* @param {object} certificate A Readable stream with certificate content. eg: fs.createReadStream()
* @param {string} name Credential name
* @param {string} description Credential description
* @returns {object} The response object
* @returns {Promise<Response>} The response object
*/
async function createCredentialDirect (url, accessToken, apiKey, certificate, name, description) {
const chunks = []
for await (const chunk of certificate) {
chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk)
}
const data = new FormData()
data.append('certificate', certificate)
data.append('certificate', new Blob([Buffer.concat(chunks)]))
data.append('name', name)
data.append('description', description)

const config = {
method: 'post',
url,
return fetch(url, {
method: 'POST',
headers: {
Authorization: 'Bearer ' + accessToken,
'content-type': 'multipart/form-data',
'x-api-key': apiKey
},
data
}
return await axios.request(config)
body: data
})
}

module.exports = {
Expand Down
33 changes: 26 additions & 7 deletions test/helpers.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ governing permissions and limitations under the License.
*/
const AioLogger = require('@adobe/aio-lib-core-logging')
const helpers = require('../src/helpers')
const axios = require('axios')
jest.mock('axios')
const stream = require('stream')
const mockedStream = new stream.Readable()
mockedStream._read = function (size) { /* do nothing */ }
Expand Down Expand Up @@ -162,18 +160,39 @@ describe('responseInterceptor', () => {
})

describe('createCredentialDirect', () => {
let fetchSpy
beforeEach(() => {
axios.mockReset()
fetchSpy = jest.spyOn(global, 'fetch').mockResolvedValue({ ok: true, status: 200 })
})
afterEach(() => {
fetchSpy.mockRestore()
})
test('API call', async () => {
const url = 'mockurl'
const accessToken = 'mockToken'
const apiKey = 'mockKey'
const name = 'mockName'
const desc = 'mock description'
axios.request.mockImplementation(() => Promise.resolve({ data: {} }))
const ret = await helpers.createCredentialDirect(url, accessToken, apiKey, mockedStream, name, desc)
expect(axios.request).toHaveBeenCalled()
expect(ret).toEqual({ data: {} })
const certStream = stream.Readable.from(Buffer.from('cert-data'))
const ret = await helpers.createCredentialDirect(url, accessToken, apiKey, certStream, name, desc)
expect(fetchSpy).toHaveBeenCalledWith(url, expect.objectContaining({
method: 'POST',
headers: expect.objectContaining({
Authorization: 'Bearer mockToken',
'x-api-key': 'mockKey'
})
}))
expect(ret).toEqual({ ok: true, status: 200 })
})
test('API call with string chunks', async () => {
const url = 'mockurl'
const accessToken = 'mockToken'
const apiKey = 'mockKey'
const name = 'mockName'
const desc = 'mock description'
const certStream = stream.Readable.from('cert-data-string')
const ret = await helpers.createCredentialDirect(url, accessToken, apiKey, certStream, name, desc)
expect(fetchSpy).toHaveBeenCalled()
expect(ret).toEqual({ ok: true, status: 200 })
})
})