@unito/integration-cli
Version:
Integration CLI
617 lines (616 loc) • 31 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const strict_1 = tslib_1.__importDefault(require("node:assert/strict"));
const tmp_1 = tslib_1.__importDefault(require("tmp"));
const fs_1 = tslib_1.__importDefault(require("fs"));
const sinon = tslib_1.__importStar(require("sinon"));
const errors_1 = require("../../src/errors");
const Configuration = tslib_1.__importStar(require("../../src/resources/configuration"));
const configurationTypes_1 = require("../../src/configurationTypes");
const errors_2 = require("../../src/errors");
const globalConfiguration_1 = require("../../src/resources/globalConfiguration");
describe('configuration', () => {
let originalConfiguration;
let tempDir;
beforeEach(async () => {
originalConfiguration = {
name: 'my-integration',
testAccounts: {
development: {
accessToken: 'foo',
},
},
};
// Create a temporary directory
tempDir = tmp_1.default.dirSync({ unsafeCleanup: true });
sinon.stub(process, 'cwd').returns(tempDir.name);
// Create the configuration file.
await fs_1.default.promises.writeFile(Configuration.getConfigurationPath(), JSON.stringify(originalConfiguration, null, 2));
});
afterEach(() => {
// Remove the temporary file
tempDir.removeCallback();
sinon.restore();
});
describe('getConfiguration', () => {
it('handles an error', async () => {
sinon.stub(fs_1.default.promises, 'readFile').throws();
try {
await Configuration.getConfiguration(globalConfiguration_1.Environment.Production);
throw Error('Should have thrown NoConfigurationFileError');
}
catch (error) {
(0, strict_1.default)(error instanceof errors_2.NoConfigurationFileError);
}
});
it('handles missing specific environment file', async () => {
const configuration = await Configuration.getConfiguration(globalConfiguration_1.Environment.Staging);
strict_1.default.equal(configuration.name, originalConfiguration.name);
});
it('returns existing specific environment file', async () => {
await fs_1.default.promises.writeFile(`${process.cwd()}/.unito.${globalConfiguration_1.Environment.Staging}.json`, JSON.stringify({
name: 'foo',
}, null, 2));
const configuration = await Configuration.getConfiguration(globalConfiguration_1.Environment.Staging);
strict_1.default.equal(configuration.name, 'foo');
});
it('throws on missing custom configuration file', async () => {
try {
await Configuration.getConfiguration(globalConfiguration_1.Environment.Staging, '/mising-config.json');
throw Error('Should have thrown NoConfigurationFileError');
}
catch (error) {
(0, strict_1.default)(error instanceof errors_2.NoConfigurationFileError);
}
});
it('returns existing specific environment file', async () => {
await fs_1.default.promises.writeFile(`${process.cwd()}/custom-config.json`, JSON.stringify({
name: 'foo',
}, null, 2));
const configuration = await Configuration.getConfiguration(globalConfiguration_1.Environment.Staging, '/custom-config.json');
strict_1.default.equal(configuration.name, 'foo');
});
it('sets default values for "oauth2"', async () => {
await fs_1.default.promises.writeFile(Configuration.getConfigurationPath(), JSON.stringify({
name: 'foo',
authorizations: [
{
name: 'bar',
method: 'oauth2',
oauth2: {
clientSecret: 'a',
clientId: 'b',
authorizationUrl: 'http://c.com',
tokenUrl: 'http://d.com',
scopes: [],
},
},
],
}, null, 2));
const configuration = await Configuration.getConfiguration(globalConfiguration_1.Environment.Production);
const oauth2 = configuration.authorizations?.at(0)?.oauth2;
strict_1.default.equal(oauth2?.requestContentType, configurationTypes_1.RequestContentType.URL_ENCODED);
strict_1.default.equal(oauth2?.responseContentType, configurationTypes_1.RequestContentType.JSON);
strict_1.default.equal(oauth2?.grantType, configurationTypes_1.GrantType.AUTHORIZATION_CODE);
});
it('accepts password grant for "oauth2"', async () => {
await fs_1.default.promises.writeFile(Configuration.getConfigurationPath(), JSON.stringify({
name: 'foo',
authorizations: [
{
name: 'bar',
method: 'oauth2',
oauth2: {
clientSecret: 'a',
clientId: 'b',
authorizationUrl: 'http://c.com',
tokenUrl: 'http://d.com',
scopes: [],
grantType: configurationTypes_1.GrantType.PASSWORD,
},
},
],
}, null, 2));
const configuration = await Configuration.getConfiguration(globalConfiguration_1.Environment.Production);
const oauth2 = configuration.authorizations?.at(0)?.oauth2;
strict_1.default.equal(oauth2?.grantType, configurationTypes_1.GrantType.PASSWORD);
});
it('accepts request parameters for "oauth2"', async () => {
await fs_1.default.promises.writeFile(Configuration.getConfigurationPath(), JSON.stringify({
name: 'foo',
authorizations: [
{
name: 'bar',
method: 'oauth2',
oauth2: {
clientSecret: 'a',
clientId: 'b',
authorizationUrl: 'http://c.com',
tokenUrl: 'http://d.com',
scopes: [],
grantType: configurationTypes_1.GrantType.PASSWORD,
tokenRequestParameters: {
header: {
a: 'yo',
},
body: {
b: false,
},
},
refreshRequestParameters: {
body: {
c: 1,
},
},
},
},
],
}, null, 2));
const configuration = await Configuration.getConfiguration(globalConfiguration_1.Environment.Production);
const oauth2 = configuration.authorizations?.at(0)?.oauth2;
strict_1.default.deepEqual(oauth2?.tokenRequestParameters, {
header: {
a: 'yo',
},
body: {
b: false,
},
});
strict_1.default.deepEqual(oauth2?.refreshRequestParameters, {
body: {
c: 1,
},
});
});
describe('validates secrets', () => {
it('valid secret', async () => {
await fs_1.default.promises.writeFile(Configuration.getConfigurationPath(), JSON.stringify({
name: 'foo',
secrets: {
foo: 'unito-secret-v1://bar',
},
}, null, 2));
const configuration = await Configuration.getConfiguration(globalConfiguration_1.Environment.Production);
strict_1.default.deepEqual(configuration.secrets, { foo: 'unito-secret-v1://bar' });
});
it('invalid secret - type', async () => {
await fs_1.default.promises.writeFile(Configuration.getConfigurationPath(), JSON.stringify({
name: 'foo',
secrets: {
foo: 123,
},
}, null, 2));
await strict_1.default.rejects(Configuration.getConfiguration(globalConfiguration_1.Environment.Production), errors_1.ConfigurationInvalid);
});
it('invalid secret - pattern', async () => {
await fs_1.default.promises.writeFile(Configuration.getConfigurationPath(), JSON.stringify({
name: 'foo',
secrets: {
foo: 'nope',
},
}, null, 2));
await strict_1.default.rejects(Configuration.getConfiguration(globalConfiguration_1.Environment.Production), errors_1.ConfigurationInvalid);
});
});
describe('validates environment variables', () => {
it('valid', async () => {
await fs_1.default.promises.writeFile(Configuration.getConfigurationPath(), JSON.stringify({
name: 'foo',
environmentVariables: {
FOO: 'unito-secret-v1://bar',
},
}, null, 2));
const configuration = await Configuration.getConfiguration(globalConfiguration_1.Environment.Production);
strict_1.default.deepEqual(configuration.environmentVariables, { FOO: 'unito-secret-v1://bar' });
});
it('invalid - type', async () => {
await fs_1.default.promises.writeFile(Configuration.getConfigurationPath(), JSON.stringify({
name: 'foo',
environmentVariables: {
FOO: 123,
},
}, null, 2));
await strict_1.default.rejects(Configuration.getConfiguration(globalConfiguration_1.Environment.Production), errors_1.ConfigurationInvalid);
});
it('invalid - key pattern', async () => {
await fs_1.default.promises.writeFile(Configuration.getConfigurationPath(), JSON.stringify({
name: 'foo',
environmentVariables: {
foo: 'nope',
},
}, null, 2));
await strict_1.default.rejects(Configuration.getConfiguration(globalConfiguration_1.Environment.Production), errors_1.ConfigurationInvalid);
});
});
describe('validates test accounts - custom', () => {
it('valid test accounts', async () => {
await fs_1.default.promises.writeFile(Configuration.getConfigurationPath(), JSON.stringify({
name: 'foo',
authorizations: [
{
name: 'apiKey',
method: 'custom',
variables: {
apiKey: {
type: 'password',
required: true,
label: 'Insert your Secret Key here',
},
displayName: {
type: 'string',
required: false,
label: 'Display Name (optional)',
},
email: {
type: 'string',
required: true,
label: 'Your Atlassian/Confluence email address',
placeholder: 'myemail@company.com',
},
domain: {
type: 'string',
required: true,
label: 'Your Confluence URL',
format: 'uri',
placeholder: 'https://mycompany.atlassian.net',
},
},
},
],
testAccounts: {
development: {
apiKey: 'xyz',
email: 'manualtester+staging@unito.io',
domain: 'https://unitomanualtests.atlassian.net',
},
compliance: {
apiKey: 'xyzw',
displayName: 'My Awesome Nickname from first grade',
email: 'manualtester+staging@unito.io',
domain: 'ftp://unitomanualtests.atlassian.net',
},
},
}, null, 2));
const configuration = await Configuration.getConfiguration(globalConfiguration_1.Environment.Production);
const developmentKey = configuration.testAccounts?.development?.apiKey;
const complianceKey = configuration.testAccounts?.compliance?.apiKey;
strict_1.default.equal(developmentKey, 'xyz');
strict_1.default.equal(complianceKey, 'xyzw');
});
it('invalid test accounts', async () => {
await fs_1.default.promises.writeFile(Configuration.getConfigurationPath(), JSON.stringify({
name: 'foo',
authorizations: [
{
name: 'apiKey',
method: 'custom',
variables: {
apiKey: {
type: 'password',
required: true,
label: 'Insert your Secret Key here',
},
displayName: {
type: 'string',
required: false,
label: 'Display Name (optional)',
},
},
},
],
testAccounts: {
development: {
apiKey: 'xyz',
displayName: 'My Awesome Nickname from first grade',
email: 'manualtester+staging@unito.io',
domain: 'ftp://unitomanualtests.atlassian.net',
},
compliance: {
APIKEY: 'xyzw',
displayName: 'My Awesome Nickname from first grade',
email: 'manualtester+staging@unito.io',
domain: 'ftp://unitomanualtests.atlassian.net',
},
},
}, null, 2));
await strict_1.default.rejects(Configuration.getConfiguration(globalConfiguration_1.Environment.Production), errors_1.ConfigurationInvalid);
});
});
describe('validates test accounts - oauth', () => {
it('valid test accounts', async () => {
await fs_1.default.promises.writeFile(Configuration.getConfigurationPath(), JSON.stringify({
name: 'foo',
authorizations: [
{
name: 'oauth2',
method: 'oauth2',
development: false,
oauth2: {
clientSecret: 'xxxxx',
clientId: 'xxxxx',
authorizationUrl: 'https://api.surveymonkey.com/oauth/authorize',
tokenUrl: 'https://api.surveymonkey.com/oauth/token',
grantType: 'authorization_code',
scopes: [
{
name: 'users_read',
},
{
name: 'surveys_read',
},
{
name: 'collectors_read',
},
{
name: 'responses_read',
},
{
name: 'contacts_read',
},
{
name: 'responses_read_detail',
},
],
requestContentType: 'application/x-www-form-urlencoded',
responseContentType: 'application/json',
},
variables: {
displayName: {
type: 'string',
required: false,
label: 'Display Name (optional)',
},
email: {
type: 'string',
required: true,
label: 'Your Atlassian/Confluence email address',
placeholder: 'myemail@company.com',
},
domain: {
type: 'string',
required: true,
label: 'Your Confluence URL',
format: 'uri',
placeholder: 'https://mycompany.atlassian.net',
},
},
},
],
testAccounts: {
development: {
accessToken: 'Super_Secret_token',
displayName: 'My Awesome Nickname from first grade',
email: 'manualtester+staging@unito.io',
domain: 'ftp://unitomanualtests.atlassian.net',
},
compliance: {
accessToken: 'Super_Secret_token_2',
email: 'manualtester+staging@unito.io',
domain: 'ftp://unitomanualtests.atlassian.net',
},
},
}, null, 2));
const configuration = await Configuration.getConfiguration(globalConfiguration_1.Environment.Production);
const developmentKey = configuration.testAccounts?.development?.accessToken;
const complianceKey = configuration.testAccounts?.compliance?.accessToken;
strict_1.default.equal(developmentKey, 'Super_Secret_token');
strict_1.default.equal(complianceKey, 'Super_Secret_token_2');
});
it('invalid test accounts', async () => {
await fs_1.default.promises.writeFile(Configuration.getConfigurationPath(), JSON.stringify({
name: 'foo',
authorizations: [
{
name: 'oauth2',
method: 'oauth2',
development: false,
oauth2: {
clientSecret: 'xxxxx',
clientId: 'xxxxx',
authorizationUrl: 'https://api.surveymonkey.com/oauth/authorize',
tokenUrl: 'https://api.surveymonkey.com/oauth/token',
grantType: 'authorization_code',
scopes: [
{
name: 'users_read',
},
{
name: 'surveys_read',
},
{
name: 'collectors_read',
},
{
name: 'responses_read',
},
{
name: 'contacts_read',
},
{
name: 'responses_read_detail',
},
],
requestContentType: 'application/x-www-form-urlencoded',
responseContentType: 'application/json',
},
},
],
testAccounts: {
development: {
apiKey: 'xyz',
},
compliance: {
apiKey: 'xyzw',
},
},
}, null, 2));
await strict_1.default.rejects(Configuration.getConfiguration(globalConfiguration_1.Environment.Production), errors_1.ConfigurationInvalid);
});
});
describe('validates test accounts - multiple authorization methods', () => {
it('valid test accounts', async () => {
await fs_1.default.promises.writeFile(Configuration.getConfigurationPath(), JSON.stringify({
name: 'foo',
authorizations: [
{
name: 'apiKey',
method: 'custom',
variables: {
apiKey: {
type: 'password',
required: true,
label: 'Insert your Secret Key here',
},
displayName: {
type: 'string',
required: false,
label: 'Display Name (optional)',
},
},
},
{
name: 'oauth2',
method: 'oauth2',
development: false,
oauth2: {
clientSecret: 'xxxxx',
clientId: 'xxxxx',
authorizationUrl: 'https://api.surveymonkey.com/oauth/authorize',
tokenUrl: 'https://api.surveymonkey.com/oauth/token',
grantType: 'authorization_code',
scopes: [
{
name: 'users_read',
},
{
name: 'surveys_read',
},
{
name: 'collectors_read',
},
{
name: 'responses_read',
},
{
name: 'contacts_read',
},
{
name: 'responses_read_detail',
},
],
requestContentType: 'application/x-www-form-urlencoded',
responseContentType: 'application/json',
},
variables: {
displayName: {
type: 'string',
required: false,
label: 'Display Name (optional)',
},
email: {
type: 'string',
required: true,
label: 'Your Atlassian/Confluence email address',
placeholder: 'myemail@company.com',
},
domain: {
type: 'string',
required: true,
label: 'Your Confluence URL',
format: 'uri',
placeholder: 'https://mycompany.atlassian.net',
},
},
},
],
testAccounts: {
development: {
accessToken: 'Super_Secret_token',
displayName: 'My Awesome Nickname from first grade',
email: 'manualtester+staging@unito.io',
domain: 'ftp://unitomanualtests.atlassian.net',
},
compliance: {
apiKey: 'Super_Secret_api_key_2',
},
},
}, null, 2));
const configuration = await Configuration.getConfiguration(globalConfiguration_1.Environment.Production);
const developmentKey = configuration.testAccounts?.development?.accessToken;
const complianceKey = configuration.testAccounts?.compliance?.apiKey;
strict_1.default.equal(developmentKey, 'Super_Secret_token');
strict_1.default.equal(complianceKey, 'Super_Secret_api_key_2');
});
it('invalid test accounts', async () => {
await fs_1.default.promises.writeFile(Configuration.getConfigurationPath(), JSON.stringify({
name: 'foo',
authorizations: [
{
name: 'apiKey',
method: 'custom',
variables: {
apiKey: {
type: 'password',
required: true,
label: 'Insert your Secret Key here',
},
displayName: {
type: 'string',
required: false,
label: 'Display Name (optional)',
},
},
},
{
name: 'oauth2',
method: 'oauth2',
development: false,
oauth2: {
clientSecret: 'xxxxx',
clientId: 'xxxxx',
authorizationUrl: 'https://api.surveymonkey.com/oauth/authorize',
tokenUrl: 'https://api.surveymonkey.com/oauth/token',
grantType: 'authorization_code',
scopes: [
{
name: 'users_read',
},
{
name: 'surveys_read',
},
{
name: 'collectors_read',
},
{
name: 'responses_read',
},
{
name: 'contacts_read',
},
{
name: 'responses_read_detail',
},
],
requestContentType: 'application/x-www-form-urlencoded',
responseContentType: 'application/json',
},
},
],
testAccounts: {
development: {
accessTokens: 'Super_Secret_token',
displayName: 'My Awesome Nickname from first grade',
email: 'manualtester+staging@unito.io',
domain: 'ftp://unitomanualtests.atlassian.net',
},
compliance: {
apiKeys: 'Super_Secret_api_key_2',
},
},
}, null, 2));
await strict_1.default.rejects(Configuration.getConfiguration(globalConfiguration_1.Environment.Production), errors_1.ConfigurationInvalid);
});
});
});
});