Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve test coverage #79

Merged
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
387 changes: 369 additions & 18 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,15 @@
},
"devDependencies": {
"@adobe/eslint-config-aio-lib-config": "^4.0.0",
"@inquirer/testing": "^2.1.19",
"@oclif/dev-cli": "^1.26.10",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"jest": "^29.7.0",
"mocha": "^10.3.0",
"nyc": "^15.1.0",
"prettier": "^3.2.5",
"proxyquire": "^2.1.3",
"sinon": "^17.0.1"
},
"bin": {
Expand Down Expand Up @@ -79,4 +80,4 @@
}
}
}
}
}
4 changes: 1 addition & 3 deletions src/lib/doRequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,7 @@ class DoRequest {
options.body = JSON.stringify(body);
options.headers['content-type'] = 'application/json';
}

const ret = fetch(url, options);
return ret;
return fetch(url, options);
}
}

Expand Down
1 change: 0 additions & 1 deletion src/lib/rde-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ async function throwOnInstallError(cloudSdkAPI, updateId, progressCallback) {
() => progressCallback(false, 'checking status')
);
progressCallback(true);

if (response.status === 200) {
const change = await response.json();
if (change) {
Expand Down
33 changes: 30 additions & 3 deletions test/commands/aem/rde/reset.test.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,50 @@
const assert = require('assert');
const sinon = require('sinon').createSandbox();
const ResetCommand = require('../../../../src/commands/aem/rde/reset.js');
const { setupLogCapturing, createCloudSdkAPIStub } = require('../../../util');
const { cli } = require('../../../../src/lib/base-command');
const ResetCommand = require('../../../../src/commands/aem/rde/reset.js');

const spinnerStartStub = sinon.stub();
const spinnerStopStub = sinon.stub();

describe('ResetCommand', function () {
setupLogCapturing(sinon, cli);

describe('#run', function () {
it('cloudSDKAPI.resetEnv() has been called', async function () {
const [command, cloudSdkApiStub] = createCloudSdkAPIStub(
let command;
let cloudSdkApiStub;
beforeEach(function () {
[command, cloudSdkApiStub] = createCloudSdkAPIStub(
sinon,
new ResetCommand([], null),
{
resetEnv: () => {},
}
);
Object.assign(command, {
spinnerStart: spinnerStartStub,
spinnerStop: spinnerStopStub,
});
});
afterEach(function () {
spinnerStartStub.reset();
spinnerStopStub.reset();
});
it('cloudSDKAPI.resetEnv() has been called', async function () {
await command.run();
assert.ok(cloudSdkApiStub.resetEnv.calledOnce);
assert.ok(spinnerStartStub.calledOnce);
});
it('stop the spinner and throw error', async function () {
let err;
try {
spinnerStartStub.throws(new Error('Failed to start a spinner'));
await command.run();
} catch (e) {
err = e;
}
assert.ok(spinnerStopStub.calledOnce);
assert.equal(err.code, 'INTERNAL_RESET_ERROR');
});
});

Expand Down
56 changes: 55 additions & 1 deletion test/commands/aem/rde/status.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
const assert = require('assert');
const sinon = require('sinon').createSandbox();
const StatusCommand = require('../../../../src/commands/aem/rde/status.js');
const { cli } = require('../../../../src/lib/base-command.js');
const Config = require('@adobe/aio-lib-core-config');
const { setupLogCapturing, createCloudSdkAPIStub } = require('../../../util');
const StatusCommand = require('../../../../src/commands/aem/rde/status.js');

const spinnerStartStub = sinon.stub();
const spinnerStopStub = sinon.stub();

const stubbedMethods = {
getArtifacts: () =>
Expand All @@ -30,6 +33,12 @@ const stubbedMethods = {
}),
};

const stubbeErrorMethods = {
getArtifacts: () => {
throw new Error('failed to get artifacts');
},
};

let command, cloudSdkApiStub;
describe('StatusCommand', function () {
setupLogCapturing(sinon, cli);
Expand Down Expand Up @@ -58,6 +67,15 @@ describe('StatusCommand', function () {
new StatusCommand([], null),
stubbedMethods
);
Object.assign(command, {
spinnerStart: spinnerStartStub,
spinnerStop: spinnerStopStub,
});
});

afterEach(function () {
spinnerStartStub.reset();
spinnerStopStub.reset();
});

it('should call getArtifacts() exactly once', async function () {
Expand Down Expand Up @@ -164,4 +182,40 @@ describe('StatusCommand', function () {
);
});
});
describe('#run exceptions', function () {
it('should stop spinner when error occurs for text mode', async function () {
[command, cloudSdkApiStub] = createCloudSdkAPIStub(
sinon,
new StatusCommand([], null),
stubbeErrorMethods
);
Object.assign(command, {
spinnerStart: spinnerStartStub,
spinnerStop: spinnerStopStub,
});
let err;
try {
await command.run();
} catch (e) {
err = e;
}
assert.ok(spinnerStopStub.calledOnce);
assert.equal(err.code, 'INTERNAL_STATUS_ERROR');
});
it('should stop spinner when error occurs for json mode', async function () {
[command, cloudSdkApiStub] = createCloudSdkAPIStub(
sinon,
new StatusCommand(['--json'], null),
stubbeErrorMethods
);
Object.assign(command, {
spinnerStart: spinnerStartStub,
spinnerStop: spinnerStopStub,
});
try {
await command.run();
} catch (e) {}
assert.ok(spinnerStopStub.calledOnce);
});
});
});
133 changes: 133 additions & 0 deletions test/lib/base-command.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ const { codes: validationCodes } = require('../../src/lib/validation-errors');
const assert = require('assert');
const sinon = require('sinon').createSandbox();
const { setupLogCapturing } = require('../util.js');
const proxyquire = require('proxyquire').noCallThru();
const jwt = require('jsonwebtoken');

describe('BaseCommand catch errors', function () {
let errorSpy;
Expand Down Expand Up @@ -185,3 +187,134 @@ describe('BaseCommand catch errors', function () {
);
});
});

describe('Authentication tests', function () {
const accessToken = jwt.sign(
{
client_id: 'jwt_client_id',
},
'pKey',
{}
);
const getOrganizationsStub = sinon.stub();
const contextGetStub = sinon.stub();
const getTokenStub = sinon.stub();
const getConfigStub = sinon.stub();
const BaseCommandAuthMock = proxyquire('../../src/lib/base-command', {
'@adobe/aio-lib-ims': {
Ims: class Ims {
getOrganizations() {
return getOrganizationsStub();
}
},
context: {
get: contextGetStub,
},
getToken: getTokenStub,
},
'@adobe/aio-lib-core-config': {
get: getConfigStub,
set: sinon.stub(),
},
'@adobe/aio-lib-cloudmanager': {
init: () => ({
getDeveloperConsoleUrl: () => 'http://example.com',
}),
},
});
beforeEach(function () {
getOrganizationsStub.returns(
Promise.resolve([
{
orgName: 'org1',
orgRef: { ident: 'org1_id', authSrc: 'org1_auth_src' },
},
{
orgName: 'org2',
orgRef: { ident: 'org2_id', authSrc: 'org2_auth_src' },
},
])
);
contextGetStub.returns({
data: {
client_id: 'client_id',
},
});
getTokenStub.returns(accessToken);
});
afterEach(function () {
getOrganizationsStub.reset();
contextGetStub.reset();
getTokenStub.reset();
getConfigStub.reset();
});
it('should be able to fetch token and api key', async function () {
const command = new BaseCommandAuthMock.BaseCommand();
const result = await command.getTokenAndKey();
assert.deepEqual(result, {
accessToken,
apiKey: 'client_id',
});
});
it('should be able to fetch cli token and api key in case of api error', async function () {
contextGetStub.returns({});
const command = new BaseCommandAuthMock.BaseCommand();
const result = await command.getTokenAndKey();
assert.deepEqual(result, { accessToken, apiKey: 'jwt_client_id' });
});
it('should throw cannot decode error', async function () {
contextGetStub.returns({});
getTokenStub.returns(undefined);
let err;
try {
const command = new BaseCommandAuthMock.BaseCommand();
await command.getTokenAndKey();
} catch (e) {
err = e;
}
assert.equal(err.code, 'CLI_AUTH_CONTEXT_CANNOT_DECODE');
});
it('should throw no client id error', async function () {
contextGetStub.returns({});
getTokenStub.returns(jwt.sign({}, 'pKey', {}));
let err;
try {
const command = new BaseCommandAuthMock.BaseCommand();
await command.getTokenAndKey();
} catch (e) {
err = e;
}
assert.equal(err.code, 'CLI_AUTH_CONTEXT_NO_CLIENT_ID');
});
it('throw error on calling runCommand method', function () {
let err;
try {
const command = new BaseCommandAuthMock.BaseCommand();
command.runCommand();
} catch (e) {
err = e;
}
assert.equal(
err.message,
'You have to implement the method runCommand(args, flags) in the subclass!'
);
});
it('should return default base url', function () {
const command = new BaseCommandAuthMock.BaseCommand();
getConfigStub.returns(undefined);
const baseUrl = command.getBaseUrl();
assert.equal(baseUrl, 'https://cloudmanager.adobe.io');
});
it('cloud sdk should be initialized properly', async function () {
const command = new BaseCommandAuthMock.BaseCommand();
const flags = {
organizationId: 'orgId',
programId: 'progId',
environmentId: 'envId',
};
command.setupParams(flags);
const callbackStub = sinon.stub();
await command.withCloudSdk(callbackStub);
assert.ok(callbackStub.calledOnce);
});
});
Loading
Loading