Skip to content

Commit

Permalink
test: more enhancements (#1190)
Browse files Browse the repository at this point in the history
## 🧰 Changes

continuing my work in #1188 with
even more work to migrate over our tests to the more comprehensive
`runCommand` helper:

- [x] `openapi convert`
- [x] `openapi inspect`
- [x] `openapi reduce`
- [x] `login`
- [x] `logout`
- [x] `whoami`

the only outstanding tests using the now deprecated
`runCommandAndReturnResult` helper are the changelog tests, but i'll
swap those out if/when we get around to migrating that command over to
APIv2.

## 🧬 QA & Testing

no functional changes. do tests still pass?
  • Loading branch information
kanadgupta authored Mar 5, 2025
1 parent f08e9c8 commit 02bd825
Show file tree
Hide file tree
Showing 14 changed files with 304 additions and 154 deletions.
77 changes: 77 additions & 0 deletions __tests__/commands/__snapshots__/login.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`rdme login > should bypass prompts and post to /login on the API if passing in every opt (no 2FA) 1`] = `
{
"result": "Successfully logged in as [email protected] to the subdomain project.",
"stderr": "",
"stdout": "",
}
`;

exports[`rdme login > should bypass prompts and post to /login on the API if passing in every opt 1`] = `
{
"result": "Successfully logged in as [email protected] to the subdomain project.",
"stderr": "",
"stdout": "",
}
`;

exports[`rdme login > should error if email is invalid 1`] = `
{
"error": [Error: You must provide a valid email address.],
"stderr": "",
"stdout": "",
}
`;

exports[`rdme login > should error if invalid credentials are given 1`] = `
{
"error": [APIv1Error: Either your email address or password is incorrect
If you need help, email support@readme.io and mention log "fake-metrics-uuid".],
"stderr": "",
"stdout": "",
}
`;

exports[`rdme login > should error if no project provided 1`] = `
{
"error": [Error: No project subdomain provided. Please use \`--project\`.],
"stderr": "",
"stdout": "",
}
`;
exports[`rdme login > should error if trying to access a project that is not yours 1`] = `
{
"error": [APIv1Error: The project (unauthorized-project) can't be found.
If you need help, email support@readme.io],
"stderr": "",
"stdout": "",
}
`;
exports[`rdme login > should make additional prompt for token if login requires 2FA 1`] = `
{
"result": "Successfully logged in as [email protected] to the subdomain project.",
"stderr": "",
"stdout": "",
}
`;
exports[`rdme login > should post to /login on the API 1`] = `
{
"result": "Successfully logged in as [email protected] to the subdomain project.",
"stderr": "",
"stdout": "",
}
`;
exports[`rdme login > should post to /login on the API if passing in project via opt 1`] = `
{
"result": "Successfully logged in as [email protected] to the subdomain project.",
"stderr": "",
"stdout": "",
}
`;
17 changes: 17 additions & 0 deletions __tests__/commands/__snapshots__/logout.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`rdme logout > should log the user out 1`] = `
{
"result": "You have logged out of ReadMe. Please use \`rdme login\` to login again.",
"stderr": "",
"stdout": "",
}
`;

exports[`rdme logout > should report the user as logged out if they aren't logged in 1`] = `
{
"result": "You have logged out of ReadMe. Please use \`rdme login\` to login again.",
"stderr": "",
"stdout": "",
}
`;
17 changes: 17 additions & 0 deletions __tests__/commands/__snapshots__/whoami.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`rdme whoami > should error if user is not authenticated 1`] = `
{
"error": [Error: Please login using \`rdme login\`.],
"stderr": "",
"stdout": "",
}
`;
exports[`rdme whoami > should return the authenticated user 1`] = `
{
"result": "You are currently logged in as [email protected] to the subdomain project.",
"stderr": "",
"stdout": "",
}
`;
33 changes: 14 additions & 19 deletions __tests__/commands/login.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import prompts from 'prompts';
import { describe, beforeAll, afterEach, it, expect } from 'vitest';

import Command from '../../src/commands/login.js';
import { APIv1Error } from '../../src/lib/apiError.js';
import configStore from '../../src/lib/configstore.js';
import { getAPIv1Mock } from '../helpers/get-api-mock.js';
import { runCommandAndReturnResult } from '../helpers/oclif.js';
import { runCommand, type OclifOutput } from '../helpers/oclif.js';

const apiKey = 'abcdefg';
const email = '[email protected]';
Expand All @@ -14,30 +13,30 @@ const project = 'subdomain';
const token = '123456';

describe('rdme login', () => {
let run: (args?: string[]) => Promise<string>;
let run: (args?: string[]) => OclifOutput;

beforeAll(() => {
run = runCommandAndReturnResult(Command);
run = runCommand(Command);
});

afterEach(() => configStore.clear());

it('should error if no project provided', () => {
prompts.inject([email, password]);
return expect(run()).rejects.toStrictEqual(new Error('No project subdomain provided. Please use `--project`.'));
return expect(run()).resolves.toMatchSnapshot();
});

it('should error if email is invalid', () => {
prompts.inject(['this-is-not-an-email', password, project]);
return expect(run()).rejects.toStrictEqual(new Error('You must provide a valid email address.'));
return expect(run()).resolves.toMatchSnapshot();
});

it('should post to /login on the API', async () => {
prompts.inject([email, password, project]);

const mock = getAPIv1Mock().post('/api/v1/login', { email, password, project }).reply(200, { apiKey });

await expect(run()).resolves.toBe('Successfully logged in as [email protected] to the subdomain project.');
await expect(run()).resolves.toMatchSnapshot();

mock.done();

Expand All @@ -51,9 +50,7 @@ describe('rdme login', () => {

const mock = getAPIv1Mock().post('/api/v1/login', { email, password, project }).reply(200, { apiKey });

await expect(run(['--project', project])).resolves.toBe(
'Successfully logged in as [email protected] to the subdomain project.',
);
await expect(run(['--project', project])).resolves.toMatchSnapshot();

mock.done();

Expand All @@ -65,9 +62,9 @@ describe('rdme login', () => {
it('should bypass prompts and post to /login on the API if passing in every opt', async () => {
const mock = getAPIv1Mock().post('/api/v1/login', { email, password, project, token }).reply(200, { apiKey });

await expect(run(['--email', email, '--password', password, '--project', project, '--otp', token])).resolves.toBe(
'Successfully logged in as [email protected] to the subdomain project.',
);
await expect(
run(['--email', email, '--password', password, '--project', project, '--otp', token]),
).resolves.toMatchSnapshot();

mock.done();

Expand All @@ -79,9 +76,7 @@ describe('rdme login', () => {
it('should bypass prompts and post to /login on the API if passing in every opt (no 2FA)', async () => {
const mock = getAPIv1Mock().post('/api/v1/login', { email, password, project }).reply(200, { apiKey });

await expect(run(['--email', email, '--password', password, '--project', project])).resolves.toBe(
'Successfully logged in as [email protected] to the subdomain project.',
);
await expect(run(['--email', email, '--password', password, '--project', project])).resolves.toMatchSnapshot();

mock.done();

Expand All @@ -101,7 +96,7 @@ describe('rdme login', () => {

const mock = getAPIv1Mock().post('/api/v1/login', { email, password, project }).reply(401, errorResponse);

await expect(run()).rejects.toStrictEqual(new APIv1Error(errorResponse));
await expect(run()).resolves.toMatchSnapshot();

mock.done();
});
Expand All @@ -121,7 +116,7 @@ describe('rdme login', () => {
.post('/api/v1/login', { email, password, project, token })
.reply(200, { apiKey });

await expect(run()).resolves.toBe('Successfully logged in as [email protected] to the subdomain project.');
await expect(run()).resolves.toMatchSnapshot();

mock.done();

Expand All @@ -144,7 +139,7 @@ describe('rdme login', () => {
.post('/api/v1/login', { email, password, project: projectThatIsNotYours })
.reply(404, errorResponse);

await expect(run()).rejects.toStrictEqual(new APIv1Error(errorResponse));
await expect(run()).resolves.toMatchSnapshot();

mock.done();
});
Expand Down
15 changes: 5 additions & 10 deletions __tests__/commands/logout.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { describe, afterEach, beforeAll, it, expect } from 'vitest';

import pkg from '../../package.json' with { type: 'json' };
import Command from '../../src/commands/logout.js';
import configStore from '../../src/lib/configstore.js';
import { runCommandAndReturnResult } from '../helpers/oclif.js';
import { runCommand, type OclifOutput } from '../helpers/oclif.js';

describe('rdme logout', () => {
let run: (args?: string[]) => Promise<string>;
let run: (args?: string[]) => OclifOutput;

beforeAll(() => {
run = runCommandAndReturnResult(Command);
run = runCommand(Command);
});

afterEach(() => {
Expand All @@ -20,18 +19,14 @@ describe('rdme logout', () => {
configStore.delete('email');
configStore.delete('project');

return expect(run()).resolves.toBe(
`You have logged out of ReadMe. Please use \`${pkg.name} login\` to login again.`,
);
return expect(run()).resolves.toMatchSnapshot();
});

it('should log the user out', async () => {
configStore.set('email', '[email protected]');
configStore.set('project', 'subdomain');

await expect(run()).resolves.toBe(
`You have logged out of ReadMe. Please use \`${pkg.name} login\` to login again.`,
);
await expect(run()).resolves.toMatchSnapshot();

expect(configStore.get('email')).toBeUndefined();
expect(configStore.get('project')).toBeUndefined();
Expand Down
30 changes: 30 additions & 0 deletions __tests__/commands/openapi/__snapshots__/convert.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`rdme openapi convert > error handling > should warn if given an OpenAPI 3.0 definition (format: json) 1`] = `
{
"result": "Your API definition has been converted and bundled and saved to output.json!",
"stderr": "- Validating the API definition located at petstore.json...
⚠️ Warning! The input file is already OpenAPI, so no conversion is necessary. Any external references will be bundled.
",
"stdout": "",
}
`;

exports[`rdme openapi convert > error handling > should warn if given an OpenAPI 3.0 definition (format: yaml) 1`] = `
{
"result": "Your API definition has been converted and bundled and saved to output.json!",
"stderr": "- Validating the API definition located at petstore.yaml...
⚠️ Warning! The input file is already OpenAPI, so no conversion is necessary. Any external references will be bundled.
",
"stdout": "",
}
`;

exports[`rdme openapi convert > should convert with no prompts via opts 1`] = `
{
"result": "Your API definition has been converted and bundled and saved to output.json!",
"stderr": "- Validating the API definition located at petstore-simple.json...
",
"stdout": "",
}
`;
21 changes: 15 additions & 6 deletions __tests__/commands/openapi/__snapshots__/inspect.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ polymorphism:
`;

exports[`rdme openapi inspect > feature reports > should generate a report for '@readme/oas-examples/3.0/json/readme-…' (w/ [ 'readme' ]) 1`] = `
"
[SoftError:
x-default: You do not use this.
x-readme.code-samples:
· #/paths/~1x-code-samples/get/x-code-samples
Expand All @@ -73,7 +73,7 @@ x-readme.samples-languages:
· node
· python
· shell
· swift"
· swift]
`;

exports[`rdme openapi inspect > feature reports > should generate a report for '@readme/oas-examples/3.0/json/schema-…' (w/ [ 'additionalProperties', …(1) ]) 1`] = `
Expand Down Expand Up @@ -103,7 +103,7 @@ circularRefs:
`;

exports[`rdme openapi inspect > feature reports > should generate a report for '@readme/oas-examples/3.0/json/schema-…' (w/ [ 'additionalProperties', …(2) ]) 1`] = `
"
[SoftError:
additionalProperties:
· #/components/schemas/BodyPart/properties/headers/additionalProperties
· #/components/schemas/BodyPart/properties/mediaType/properties/parameters/additionalProperties
Expand Down Expand Up @@ -132,11 +132,11 @@ x-readme.code-samples: You do not use this.
x-readme.headers: You do not use this.
x-readme.explorer-enabled: You do not use this.
x-readme.proxy-enabled: You do not use this.
x-readme.samples-languages: You do not use this."
x-readme.samples-languages: You do not use this.]
`;

exports[`rdme openapi inspect > feature reports > should generate a report for '@readme/oas-examples/3.0/json/schema-…' (w/ [ 'circularRefs', 'readme' ]) 1`] = `
"
[SoftError:
circularRefs:
· #/components/schemas/BodyPart/properties/parent
· #/components/schemas/MultiPart/properties/bodyParts/items
Expand All @@ -151,7 +151,7 @@ x-readme.code-samples: You do not use this.
x-readme.headers: You do not use this.
x-readme.explorer-enabled: You do not use this.
x-readme.proxy-enabled: You do not use this.
x-readme.samples-languages: You do not use this."
x-readme.samples-languages: You do not use this.]
`;

exports[`rdme openapi inspect > feature reports > should generate a report for '@readme/oas-examples/3.1/json/train-t…' (w/ [ 'commonParameters' ]) 1`] = `
Expand All @@ -161,6 +161,15 @@ commonParameters:
· #/paths/~1bookings~1{bookingId}~1payment/parameters"
`;

exports[`rdme openapi inspect > feature reports > should throw an error if an invalid feature is supplied 1`] = `
{
"error": [Error: Expected --feature=reamde to be one of: additionalProperties, callbacks, circularRefs, commonParameters, discriminators, links, style, polymorphism, serverVariables, webhooks, xml, readme
See more help with --help],
"stderr": "",
"stdout": "",
}
`;

exports[`rdme openapi inspect > full reports > should generate a report for @readme/oas-examples/3.0/json/petstore.json 1`] = `
"Here are some interesting things we found in your API definition. 🕵️
Expand Down
Loading

0 comments on commit 02bd825

Please sign in to comment.