From 988df1d83345edb10cd49be3dd3db94128d99775 Mon Sep 17 00:00:00 2001 From: Kanad Gupta <8854718+kanadgupta@users.noreply.github.com> Date: Fri, 22 Nov 2024 10:27:17 -0600 Subject: [PATCH 1/2] docs: fix contributing docs up a bit (#1083) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 🧰 Changes a few contributing doc cleanups, some of which i forgot to include in https://github.com/readmeio/rdme/pull/1081. --- CONTRIBUTING.md | 10 ++++------ MAINTAINERS.md | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0fbf00962..e828a3f99 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,15 +8,13 @@ To get started, run the `build` script to create a symlink with `package.json` ( npm run build ``` -To run test commands, use `./bin/dev.js` instead of `rdme`. For example, if the command you're testing looks like this... +To run test commands, swap out `rdme` for `bin/dev.js`. For example: ```sh +# if the production command you're testing looks like this... rdme openapi:validate __tests__/__fixtures__/ref-oas/petstore.json -``` - -... your local command will look like this: -```sh +# ... your local test command will look like this: bin/dev.js openapi:validate __tests__/__fixtures__/ref-oas/petstore.json ``` @@ -32,7 +30,7 @@ npm run build bin/run.js openapi:validate __tests__/__fixtures__/ref-oas/petstore.json ``` -Your changes to the command code may make changes to [the command reference document](./documentation/commands.md) — it is up to you whether you include those changes in your PR or if you let the release process take care of it. More information on that can be found in [MAINTAINERS.md](./MAINTAINERS.md). +Your changes to the command code may make changes to [the command reference documents](./documentation/commands) — it is up to you whether you include those changes in your PR or if you let the release process take care of it. More information on that can be found in [`MAINTAINERS.md`](./MAINTAINERS.md). ## Running GitHub Actions Locally 🐳 diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 53af55189..06a824cbd 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -15,7 +15,7 @@ When code is merged into the `main` or `next` branches, a release workflow (powe - Based on the changes, the version is bumped in [`package.json`](./package.json) 🥊 For example, say the current version is `8.5.1` and the commit history includes a new feature. This would result in a minor semver bump, which would produce the following tags: - A release tag like `v8.6.0` if on the `main` branch - A prerelease tag like `v8.6.0-next.1` if on the `next` branch -- A few other files, such as [`CHANGELOG.md`](./CHANGELOG.md), [the command reference page](./documentation/commands.md), and our GitHub Actions bundle files, are updated based on this code 🪵 +- A few other files, such as [`CHANGELOG.md`](./CHANGELOG.md), [the command reference pages](./documentation/commands), and our GitHub Actions bundle files, are updated based on this code 🪵 - A build commit (like [this](https://github.com/readmeio/rdme/commit/533a2db50b39c3b6130b3af07bebaed38218db4c)) is created with all of the updated files (e.g., `package.json`, `CHANGELOG.md`, etc.) 🆕 - A couple duplicated tags are created for the current commit so our users can refer to them differently in their GitHub Actions (e.g., `8.6.0`, `v8`) 🔖 - The new commit and tags are pushed to GitHub 📌 From 78085269c3276b6ed840efbfcc7a85636b0e6f04 Mon Sep 17 00:00:00 2001 From: Kanad Gupta <8854718+kanadgupta@users.noreply.github.com> Date: Fri, 22 Nov 2024 17:00:20 -0600 Subject: [PATCH 2/2] test: rework how we assert command results (#1084) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 🧰 Changes this PR is a slight rework to how we assert command results using `@oclif/test` (inspired by https://github.com/oclif/test/issues/655). we use a mishmash of our own internal logger vs `oclif`'s `this.log` and this sets us up for better success when we eventually unify all of this in v10. this also touches up our vitest setup a bit — hiding Node.js `ExperimentalWarning` outputs, removing an unused matcher, only importing a matcher where we use it, etc. our vitest output has been a bit of a mess lately so all of these changes culminate in a much cleaner output and i'm irrationally excited about it. <details><summary>before</summary> ![CleanShot 2024-11-22 at 10 55 54@2x](https://github.com/user-attachments/assets/fe57bf53-279b-4b56-8e28-d3dc0382cc9e) </details> <details><summary>after</summary> ![CleanShot 2024-11-22 at 10 55 21@2x](https://github.com/user-attachments/assets/e79cddb2-2238-43d0-bfa5-444281c64ee7) </details> ## 🧬 QA & Testing no functional changes nor changes in test coverage — if tests still pass we should be in good shape. --- __tests__/commands/categories/create.test.ts | 4 +- __tests__/commands/categories/index.test.ts | 4 +- __tests__/commands/changelogs/index.test.ts | 4 +- __tests__/commands/changelogs/single.test.ts | 4 +- __tests__/commands/custompages/index.test.ts | 4 +- __tests__/commands/custompages/single.test.ts | 4 +- __tests__/commands/docs/index.test.ts | 4 +- __tests__/commands/docs/multiple.test.ts | 4 +- __tests__/commands/docs/prune.test.ts | 4 +- __tests__/commands/docs/single.test.ts | 4 +- __tests__/commands/login.test.ts | 4 +- __tests__/commands/logout.test.ts | 4 +- __tests__/commands/open.test.ts | 4 +- __tests__/commands/openapi/convert.test.ts | 4 +- __tests__/commands/openapi/index.test.ts | 4 +- __tests__/commands/openapi/inspect.test.ts | 4 +- __tests__/commands/openapi/reduce.test.ts | 4 +- __tests__/commands/openapi/validate.test.ts | 4 +- __tests__/commands/versions/create.test.ts | 4 +- __tests__/commands/versions/delete.test.ts | 4 +- __tests__/commands/versions/index.test.ts | 4 +- __tests__/commands/versions/update.test.ts | 4 +- __tests__/commands/whoami.test.ts | 4 +- __tests__/helpers/oclif.ts | 69 +++++++++++++++++++ __tests__/helpers/setup-oclif-config.ts | 49 ------------- __tests__/helpers/vitest.matchers.ts | 27 +------- __tests__/lib/createGHA.test.ts | 9 ++- vitest.config.ts | 10 +-- 28 files changed, 128 insertions(+), 128 deletions(-) create mode 100644 __tests__/helpers/oclif.ts delete mode 100644 __tests__/helpers/setup-oclif-config.ts diff --git a/__tests__/commands/categories/create.test.ts b/__tests__/commands/categories/create.test.ts index 6d756802b..3c692aadb 100644 --- a/__tests__/commands/categories/create.test.ts +++ b/__tests__/commands/categories/create.test.ts @@ -3,7 +3,7 @@ import { describe, beforeAll, afterEach, it, expect } from 'vitest'; import Command from '../../../src/commands/categories/create.js'; import { getAPIV1Mock, getAPIV1MockWithVersionHeader } from '../../helpers/get-api-mock.js'; -import { runCommand } from '../../helpers/setup-oclif-config.js'; +import { runCommandAndReturnResult } from '../../helpers/oclif.js'; const key = 'API_KEY'; const version = '1.0.0'; @@ -12,8 +12,8 @@ describe('rdme categories:create', () => { let run: (args?: string[]) => Promise<string>; beforeAll(() => { - run = runCommand(Command); nock.disableNetConnect(); + run = runCommandAndReturnResult(Command); }); afterEach(() => nock.cleanAll()); diff --git a/__tests__/commands/categories/index.test.ts b/__tests__/commands/categories/index.test.ts index 51d9a5311..c1b14b69e 100644 --- a/__tests__/commands/categories/index.test.ts +++ b/__tests__/commands/categories/index.test.ts @@ -3,7 +3,7 @@ import { describe, beforeAll, afterEach, it, expect } from 'vitest'; import Command from '../../../src/commands/categories/index.js'; import { getAPIV1Mock, getAPIV1MockWithVersionHeader } from '../../helpers/get-api-mock.js'; -import { runCommand } from '../../helpers/setup-oclif-config.js'; +import { runCommandAndReturnResult } from '../../helpers/oclif.js'; const key = 'API_KEY'; const version = '1.0.0'; @@ -13,7 +13,7 @@ describe('rdme categories', () => { beforeAll(() => { nock.disableNetConnect(); - run = runCommand(Command); + run = runCommandAndReturnResult(Command); }); afterEach(() => nock.cleanAll()); diff --git a/__tests__/commands/changelogs/index.test.ts b/__tests__/commands/changelogs/index.test.ts index fab366e59..5e475b546 100644 --- a/__tests__/commands/changelogs/index.test.ts +++ b/__tests__/commands/changelogs/index.test.ts @@ -10,7 +10,7 @@ import Command from '../../../src/commands/changelogs.js'; import { APIv1Error } from '../../../src/lib/apiError.js'; import { getAPIV1Mock } from '../../helpers/get-api-mock.js'; import hashFileContents from '../../helpers/hash-file-contents.js'; -import { runCommand } from '../../helpers/setup-oclif-config.js'; +import { runCommandAndReturnResult } from '../../helpers/oclif.js'; const fixturesBaseDir = '__fixtures__/changelogs'; const fullFixturesDir = `${__dirname}./../../${fixturesBaseDir}`; @@ -21,7 +21,7 @@ describe('rdme changelogs', () => { beforeAll(() => { nock.disableNetConnect(); - run = runCommand(Command); + run = runCommandAndReturnResult(Command); }); afterAll(() => nock.cleanAll()); diff --git a/__tests__/commands/changelogs/single.test.ts b/__tests__/commands/changelogs/single.test.ts index 765c74960..be6356eca 100644 --- a/__tests__/commands/changelogs/single.test.ts +++ b/__tests__/commands/changelogs/single.test.ts @@ -10,7 +10,7 @@ import Command from '../../../src/commands/changelogs.js'; import { APIv1Error } from '../../../src/lib/apiError.js'; import { getAPIV1Mock } from '../../helpers/get-api-mock.js'; import hashFileContents from '../../helpers/hash-file-contents.js'; -import { runCommand } from '../../helpers/setup-oclif-config.js'; +import { runCommandAndReturnResult } from '../../helpers/oclif.js'; const fixturesBaseDir = '__fixtures__/changelogs'; const fullFixturesDir = `${__dirname}./../../${fixturesBaseDir}`; @@ -21,7 +21,7 @@ describe('rdme changelogs (single)', () => { beforeAll(() => { nock.disableNetConnect(); - run = runCommand(Command); + run = runCommandAndReturnResult(Command); }); afterAll(() => nock.cleanAll()); diff --git a/__tests__/commands/custompages/index.test.ts b/__tests__/commands/custompages/index.test.ts index d89f989f4..f5bdfe1b0 100644 --- a/__tests__/commands/custompages/index.test.ts +++ b/__tests__/commands/custompages/index.test.ts @@ -10,7 +10,7 @@ import Command from '../../../src/commands/custompages.js'; import { APIv1Error } from '../../../src/lib/apiError.js'; import { getAPIV1Mock } from '../../helpers/get-api-mock.js'; import hashFileContents from '../../helpers/hash-file-contents.js'; -import { runCommand } from '../../helpers/setup-oclif-config.js'; +import { runCommandAndReturnResult } from '../../helpers/oclif.js'; const fixturesBaseDir = '__fixtures__/custompages'; const fullFixturesDir = `${__dirname}./../../${fixturesBaseDir}`; @@ -21,7 +21,7 @@ describe('rdme custompages', () => { beforeAll(() => { nock.disableNetConnect(); - run = runCommand(Command); + run = runCommandAndReturnResult(Command); }); afterAll(() => nock.cleanAll()); diff --git a/__tests__/commands/custompages/single.test.ts b/__tests__/commands/custompages/single.test.ts index bffb22dfa..0bdd184de 100644 --- a/__tests__/commands/custompages/single.test.ts +++ b/__tests__/commands/custompages/single.test.ts @@ -10,7 +10,7 @@ import Command from '../../../src/commands/custompages.js'; import { APIv1Error } from '../../../src/lib/apiError.js'; import { getAPIV1Mock } from '../../helpers/get-api-mock.js'; import hashFileContents from '../../helpers/hash-file-contents.js'; -import { runCommand } from '../../helpers/setup-oclif-config.js'; +import { runCommandAndReturnResult } from '../../helpers/oclif.js'; const fixturesBaseDir = '__fixtures__/custompages'; const fullFixturesDir = `${__dirname}./../../${fixturesBaseDir}`; @@ -21,7 +21,7 @@ describe('rdme custompages (single)', () => { beforeAll(() => { nock.disableNetConnect(); - run = runCommand(Command); + run = runCommandAndReturnResult(Command); }); afterAll(() => nock.cleanAll()); diff --git a/__tests__/commands/docs/index.test.ts b/__tests__/commands/docs/index.test.ts index d5e86759e..36bd86ebe 100644 --- a/__tests__/commands/docs/index.test.ts +++ b/__tests__/commands/docs/index.test.ts @@ -14,8 +14,8 @@ import { APIv1Error } from '../../../src/lib/apiError.js'; import { getAPIV1Mock, getAPIV1MockWithVersionHeader } from '../../helpers/get-api-mock.js'; import { after, before } from '../../helpers/get-gha-setup.js'; import hashFileContents from '../../helpers/hash-file-contents.js'; +import { runCommandAndReturnResult, runCommandWithHooks } from '../../helpers/oclif.js'; import { after as afterGHAEnv, before as beforeGHAEnv } from '../../helpers/setup-gha-env.js'; -import { runCommand, runCommandWithHooks } from '../../helpers/setup-oclif-config.js'; const fixturesBaseDir = '__fixtures__/docs'; const fullFixturesDir = `${__dirname}./../../${fixturesBaseDir}`; @@ -29,7 +29,7 @@ describe('rdme docs', () => { beforeAll(() => { nock.disableNetConnect(); - run = runCommand(Command); + run = runCommandAndReturnResult(Command); }); afterAll(() => nock.cleanAll()); diff --git a/__tests__/commands/docs/multiple.test.ts b/__tests__/commands/docs/multiple.test.ts index 65beca3d8..2f2d87726 100644 --- a/__tests__/commands/docs/multiple.test.ts +++ b/__tests__/commands/docs/multiple.test.ts @@ -8,7 +8,7 @@ import { describe, beforeAll, afterAll, it, expect } from 'vitest'; import Command from '../../../src/commands/docs/index.js'; import { getAPIV1Mock, getAPIV1MockWithVersionHeader } from '../../helpers/get-api-mock.js'; import hashFileContents from '../../helpers/hash-file-contents.js'; -import { runCommand } from '../../helpers/setup-oclif-config.js'; +import { runCommandAndReturnResult } from '../../helpers/oclif.js'; const fixturesBaseDir = '__fixtures__/docs'; const fullFixturesDir = `${__dirname}./../../${fixturesBaseDir}`; @@ -21,7 +21,7 @@ describe('rdme docs (multiple)', () => { beforeAll(() => { nock.disableNetConnect(); - run = runCommand(Command); + run = runCommandAndReturnResult(Command); }); afterAll(() => nock.cleanAll()); diff --git a/__tests__/commands/docs/prune.test.ts b/__tests__/commands/docs/prune.test.ts index f25946f64..1211098fc 100644 --- a/__tests__/commands/docs/prune.test.ts +++ b/__tests__/commands/docs/prune.test.ts @@ -4,7 +4,7 @@ import { describe, beforeAll, afterAll, it, expect } from 'vitest'; import Command from '../../../src/commands/docs/prune.js'; import { getAPIV1Mock, getAPIV1MockWithVersionHeader } from '../../helpers/get-api-mock.js'; -import { runCommand, runCommandWithHooks } from '../../helpers/setup-oclif-config.js'; +import { runCommandAndReturnResult, runCommandWithHooks } from '../../helpers/oclif.js'; const fixturesBaseDir = '__fixtures__/docs'; @@ -17,7 +17,7 @@ describe('rdme docs:prune', () => { beforeAll(() => { nock.disableNetConnect(); - run = runCommand(Command); + run = runCommandAndReturnResult(Command); }); afterAll(() => nock.cleanAll()); diff --git a/__tests__/commands/docs/single.test.ts b/__tests__/commands/docs/single.test.ts index e9e30fef2..fa9fac305 100644 --- a/__tests__/commands/docs/single.test.ts +++ b/__tests__/commands/docs/single.test.ts @@ -10,8 +10,8 @@ import Command from '../../../src/commands/docs/index.js'; import { APIv1Error } from '../../../src/lib/apiError.js'; import { getAPIV1Mock, getAPIV1MockWithVersionHeader } from '../../helpers/get-api-mock.js'; import hashFileContents from '../../helpers/hash-file-contents.js'; +import { runCommandAndReturnResult } from '../../helpers/oclif.js'; import { after as afterGHAEnv, before as beforeGHAEnv } from '../../helpers/setup-gha-env.js'; -import { runCommand } from '../../helpers/setup-oclif-config.js'; const fixturesBaseDir = '__fixtures__/docs'; const fullFixturesDir = `${__dirname}./../../${fixturesBaseDir}`; @@ -25,7 +25,7 @@ describe('rdme docs (single)', () => { beforeAll(() => { nock.disableNetConnect(); - run = runCommand(Command); + run = runCommandAndReturnResult(Command); }); afterAll(() => nock.cleanAll()); diff --git a/__tests__/commands/login.test.ts b/__tests__/commands/login.test.ts index eca319582..24d09c400 100644 --- a/__tests__/commands/login.test.ts +++ b/__tests__/commands/login.test.ts @@ -6,7 +6,7 @@ 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 { runCommand } from '../helpers/setup-oclif-config.js'; +import { runCommandAndReturnResult } from '../helpers/oclif.js'; const apiKey = 'abcdefg'; const email = 'user@example.com'; @@ -19,7 +19,7 @@ describe('rdme login', () => { beforeAll(() => { nock.disableNetConnect(); - run = runCommand(Command); + run = runCommandAndReturnResult(Command); }); afterEach(() => configStore.clear()); diff --git a/__tests__/commands/logout.test.ts b/__tests__/commands/logout.test.ts index fedd119e5..b0fab24e6 100644 --- a/__tests__/commands/logout.test.ts +++ b/__tests__/commands/logout.test.ts @@ -3,13 +3,13 @@ import { describe, afterEach, beforeAll, it, expect } from 'vitest'; import pkg from '../../package.json'; import Command from '../../src/commands/logout.js'; import configStore from '../../src/lib/configstore.js'; -import { runCommand } from '../helpers/setup-oclif-config.js'; +import { runCommandAndReturnResult } from '../helpers/oclif.js'; describe('rdme logout', () => { let run: (args?: string[]) => Promise<string>; beforeAll(() => { - run = runCommand(Command); + run = runCommandAndReturnResult(Command); }); afterEach(() => { diff --git a/__tests__/commands/open.test.ts b/__tests__/commands/open.test.ts index e26609b9d..ccb0a6102 100644 --- a/__tests__/commands/open.test.ts +++ b/__tests__/commands/open.test.ts @@ -7,7 +7,7 @@ import pkg from '../../package.json'; import Command from '../../src/commands/open.js'; import configStore from '../../src/lib/configstore.js'; import { getAPIV1Mock } from '../helpers/get-api-mock.js'; -import { runCommand } from '../helpers/setup-oclif-config.js'; +import { runCommandAndReturnResult } from '../helpers/oclif.js'; const mockArg = ['--mock']; @@ -15,7 +15,7 @@ describe('rdme open', () => { let run: (args?: string[]) => Promise<string>; beforeAll(() => { - run = runCommand(Command); + run = runCommandAndReturnResult(Command); }); afterEach(() => { diff --git a/__tests__/commands/openapi/convert.test.ts b/__tests__/commands/openapi/convert.test.ts index 672bcd240..f2c5ae805 100644 --- a/__tests__/commands/openapi/convert.test.ts +++ b/__tests__/commands/openapi/convert.test.ts @@ -4,7 +4,7 @@ import prompts from 'prompts'; import { describe, it, expect, vi, beforeAll, beforeEach, afterEach } from 'vitest'; import Command from '../../../src/commands/openapi/convert.js'; -import { runCommand } from '../../helpers/setup-oclif-config.js'; +import { runCommandAndReturnResult } from '../../helpers/oclif.js'; const successfulConversion = () => 'Your API definition has been converted and bundled and saved to output.json!'; @@ -13,7 +13,7 @@ describe('rdme openapi:convert', () => { let testWorkingDir: string; beforeAll(() => { - run = runCommand(Command); + run = runCommandAndReturnResult(Command); }); beforeEach(() => { diff --git a/__tests__/commands/openapi/index.test.ts b/__tests__/commands/openapi/index.test.ts index acdc902cd..3a39557c4 100644 --- a/__tests__/commands/openapi/index.test.ts +++ b/__tests__/commands/openapi/index.test.ts @@ -13,8 +13,8 @@ import config from '../../../src/lib/config.js'; import petstoreWeird from '../../__fixtures__/petstore-simple-weird-version.json' with { type: 'json' }; import { getAPIV1Mock, getAPIV1MockWithVersionHeader } from '../../helpers/get-api-mock.js'; import { after, before } from '../../helpers/get-gha-setup.js'; +import { runCommandAndReturnResult } from '../../helpers/oclif.js'; import { after as afterGHAEnv, before as beforeGHAEnv } from '../../helpers/setup-gha-env.js'; -import { runCommand } from '../../helpers/setup-oclif-config.js'; let consoleInfoSpy: MockInstance; let consoleWarnSpy: MockInstance; @@ -55,7 +55,7 @@ describe('rdme openapi', () => { beforeAll(() => { nock.disableNetConnect(); - run = runCommand(Command); + run = runCommandAndReturnResult(Command); }); beforeEach(() => { diff --git a/__tests__/commands/openapi/inspect.test.ts b/__tests__/commands/openapi/inspect.test.ts index 72a1182ac..b03f04c7f 100644 --- a/__tests__/commands/openapi/inspect.test.ts +++ b/__tests__/commands/openapi/inspect.test.ts @@ -5,13 +5,13 @@ import assert from 'node:assert'; import { describe, it, expect, beforeAll } from 'vitest'; import Command from '../../../src/commands/openapi/inspect.js'; -import { runCommand } from '../../helpers/setup-oclif-config.js'; +import { runCommandAndReturnResult } from '../../helpers/oclif.js'; describe('rdme openapi:inspect', () => { let run: (args?: string[]) => Promise<unknown>; beforeAll(() => { - run = runCommand(Command); + run = runCommandAndReturnResult(Command); }); describe('full reports', () => { diff --git a/__tests__/commands/openapi/reduce.test.ts b/__tests__/commands/openapi/reduce.test.ts index df4acbcc6..428cddcb8 100644 --- a/__tests__/commands/openapi/reduce.test.ts +++ b/__tests__/commands/openapi/reduce.test.ts @@ -6,7 +6,7 @@ import prompts from 'prompts'; import { describe, beforeAll, beforeEach, afterEach, it, expect, vi, type MockInstance } from 'vitest'; import Command from '../../../src/commands/openapi/reduce.js'; -import { runCommand } from '../../helpers/setup-oclif-config.js'; +import { runCommandAndReturnResult } from '../../helpers/oclif.js'; const successfulReduction = () => 'Your reduced API definition has been saved to output.json! 🤏'; @@ -18,7 +18,7 @@ describe('rdme openapi:reduce', () => { let testWorkingDir: string; beforeAll(() => { - run = runCommand(Command); + run = runCommandAndReturnResult(Command); }); beforeEach(() => { diff --git a/__tests__/commands/openapi/validate.test.ts b/__tests__/commands/openapi/validate.test.ts index 06e52fb3d..534e66869 100644 --- a/__tests__/commands/openapi/validate.test.ts +++ b/__tests__/commands/openapi/validate.test.ts @@ -8,7 +8,7 @@ import { describe, beforeAll, beforeEach, afterEach, it, expect, vi, type MockIn import Command from '../../../src/commands/openapi/validate.js'; import { after, before } from '../../helpers/get-gha-setup.js'; -import { runCommand, runCommandWithHooks } from '../../helpers/setup-oclif-config.js'; +import { runCommandAndReturnResult, runCommandWithHooks } from '../../helpers/oclif.js'; let consoleInfoSpy: MockInstance; @@ -21,7 +21,7 @@ describe('rdme openapi:validate', () => { let testWorkingDir: string; beforeAll(() => { - run = runCommand(Command); + run = runCommandAndReturnResult(Command); }); beforeEach(() => { diff --git a/__tests__/commands/versions/create.test.ts b/__tests__/commands/versions/create.test.ts index 0969fb031..c85c73755 100644 --- a/__tests__/commands/versions/create.test.ts +++ b/__tests__/commands/versions/create.test.ts @@ -5,7 +5,7 @@ import { describe, beforeAll, afterEach, it, expect } from 'vitest'; import Command from '../../../src/commands/versions/create.js'; import { APIv1Error } from '../../../src/lib/apiError.js'; import { getAPIV1Mock } from '../../helpers/get-api-mock.js'; -import { runCommand } from '../../helpers/setup-oclif-config.js'; +import { runCommandAndReturnResult } from '../../helpers/oclif.js'; const key = 'API_KEY'; const version = '1.0.0'; @@ -15,7 +15,7 @@ describe('rdme versions:create', () => { beforeAll(() => { nock.disableNetConnect(); - run = runCommand(Command); + run = runCommandAndReturnResult(Command); }); afterEach(() => nock.cleanAll()); diff --git a/__tests__/commands/versions/delete.test.ts b/__tests__/commands/versions/delete.test.ts index e11041184..c0692bac3 100644 --- a/__tests__/commands/versions/delete.test.ts +++ b/__tests__/commands/versions/delete.test.ts @@ -4,7 +4,7 @@ import { describe, beforeAll, afterEach, it, expect } from 'vitest'; import Command from '../../../src/commands/versions/delete.js'; import { APIv1Error } from '../../../src/lib/apiError.js'; import { getAPIV1Mock } from '../../helpers/get-api-mock.js'; -import { runCommand } from '../../helpers/setup-oclif-config.js'; +import { runCommandAndReturnResult } from '../../helpers/oclif.js'; const key = 'API_KEY'; const version = '1.0.0'; @@ -14,7 +14,7 @@ describe('rdme versions:delete', () => { beforeAll(() => { nock.disableNetConnect(); - run = runCommand(Command); + run = runCommandAndReturnResult(Command); }); afterEach(() => nock.cleanAll()); diff --git a/__tests__/commands/versions/index.test.ts b/__tests__/commands/versions/index.test.ts index a98e363cc..04f170837 100644 --- a/__tests__/commands/versions/index.test.ts +++ b/__tests__/commands/versions/index.test.ts @@ -5,7 +5,7 @@ import { describe, beforeAll, afterEach, it, expect } from 'vitest'; import Command from '../../../src/commands/versions/index.js'; import { getAPIV1Mock } from '../../helpers/get-api-mock.js'; -import { runCommand } from '../../helpers/setup-oclif-config.js'; +import { runCommandAndReturnResult } from '../../helpers/oclif.js'; const key = 'API_KEY'; const version = '1.0.0'; @@ -36,7 +36,7 @@ describe('rdme versions', () => { beforeAll(() => { nock.disableNetConnect(); - run = runCommand(Command); + run = runCommandAndReturnResult(Command); }); afterEach(() => nock.cleanAll()); diff --git a/__tests__/commands/versions/update.test.ts b/__tests__/commands/versions/update.test.ts index 5d225df0b..6be05bd2f 100644 --- a/__tests__/commands/versions/update.test.ts +++ b/__tests__/commands/versions/update.test.ts @@ -5,7 +5,7 @@ import { describe, beforeAll, afterEach, it, expect } from 'vitest'; import Command from '../../../src/commands/versions/update.js'; import { APIv1Error } from '../../../src/lib/apiError.js'; import { getAPIV1Mock } from '../../helpers/get-api-mock.js'; -import { runCommand } from '../../helpers/setup-oclif-config.js'; +import { runCommandAndReturnResult } from '../../helpers/oclif.js'; const key = 'API_KEY'; const version = '1.0.0'; @@ -15,7 +15,7 @@ describe('rdme versions:update', () => { beforeAll(() => { nock.disableNetConnect(); - run = runCommand(Command); + run = runCommandAndReturnResult(Command); }); afterEach(() => nock.cleanAll()); diff --git a/__tests__/commands/whoami.test.ts b/__tests__/commands/whoami.test.ts index c3172a909..10c898255 100644 --- a/__tests__/commands/whoami.test.ts +++ b/__tests__/commands/whoami.test.ts @@ -3,13 +3,13 @@ import { describe, afterEach, it, expect, beforeAll } from 'vitest'; import pkg from '../../package.json'; import Command from '../../src/commands/whoami.js'; import configStore from '../../src/lib/configstore.js'; -import { runCommand } from '../helpers/setup-oclif-config.js'; +import { runCommandAndReturnResult } from '../helpers/oclif.js'; describe('rdme whoami', () => { let run: (args?: string[]) => Promise<string>; beforeAll(() => { - run = runCommand(Command); + run = runCommandAndReturnResult(Command); }); afterEach(() => { diff --git a/__tests__/helpers/oclif.ts b/__tests__/helpers/oclif.ts new file mode 100644 index 000000000..a6ec356c4 --- /dev/null +++ b/__tests__/helpers/oclif.ts @@ -0,0 +1,69 @@ +import type { Command as OclifCommand } from '@oclif/core'; + +import path from 'node:path'; + +import { Config } from '@oclif/core'; +import { captureOutput, runCommand as oclifRunCommand } from '@oclif/test'; + +const testNodeEnv = process.env.NODE_ENV; + +/** + * Used for setting up the oclif configuration for simulating commands in tests. + * This is a really barebones approach so we can continue using vitest + nock + * how we want to. + * + * @see {@link https://github.com/oclif/test} + * @see {@link https://oclif.io/docs/testing} + */ +export function setupOclifConfig() { + // https://stackoverflow.com/a/61829368 + const root = path.join(new URL('.', import.meta.url).pathname, '.'); + + return Config.load({ + root, + version: '7.0.0', + }); +} + +/** + * This runs the command you pass in against the args you pass in. + * This helper is preferred because `vitest --watch` will properly reload + * when you make changes to your command. + * + * @example runCommand(LoginCommand)(['--email', 'owlbert@example.com', '--password', 'password']) + */ +function runCommand<T extends typeof OclifCommand>(Command: T) { + return async function runCommandAgainstArgs(args?: string[]) { + const oclifConfig = await setupOclifConfig(); + // @ts-expect-error this is the pattern recommended by the @oclif/test docs. + // Not sure how to get this working with type generics. + return captureOutput<string>(() => Command.run(args, oclifConfig), { testNodeEnv }); + }; +} + +/** + * A slight variation on `runCommand` that returns the result of the command and throws + * an error if the command throws one. Mainly a helper to minimize the amount of refactoring + * in our existing tests. + * + * @example runCommandAndReturnResult(LoginCommand)(['--email', 'owlbert@example.com', '--password', 'password']) + */ +export function runCommandAndReturnResult<T extends typeof OclifCommand>(Command: T) { + return async function runCommandAgainstArgs(args?: string[]) { + const { error, result } = await runCommand(Command)(args); + if (error) { + throw error; + } + return result; + }; +} + +/** + * This runs the command you pass in against the args you pass in. + * This helper is not ideal in that `vitest --watch` won't reload, + * but it's helpful if you need to run assertions against the command's hooks. + */ +export async function runCommandWithHooks(args?: string[]) { + const oclifConfig = await setupOclifConfig(); + return oclifRunCommand(args, oclifConfig, { testNodeEnv }); +} diff --git a/__tests__/helpers/setup-oclif-config.ts b/__tests__/helpers/setup-oclif-config.ts deleted file mode 100644 index 47041f9e8..000000000 --- a/__tests__/helpers/setup-oclif-config.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { Command as OclifCommand } from '@oclif/core'; - -import path from 'node:path'; - -import { Config } from '@oclif/core'; -import { captureOutput, runCommand as oclifRunCommand } from '@oclif/test'; - -const testNodeEnv = process.env.NODE_ENV; - -/** - * Used for setting up the oclif configuration for simulating commands in tests. - * This is a really barebones approach so we can continue using vitest + nock - * how we want to. - * - * @see {@link https://github.com/oclif/test} - * @see {@link https://oclif.io/docs/testing} - */ -export default function setupOclifConfig() { - // https://stackoverflow.com/a/61829368 - const root = path.join(new URL('.', import.meta.url).pathname, '.'); - - return Config.load({ - root, - version: '7.0.0', - }); -} - -export function runCommand<T extends typeof OclifCommand>(Command: T) { - return async function runCommandAgainstArgs(args?: string[]) { - const oclifConfig = await setupOclifConfig(); - // @ts-expect-error this is the pattern recommended by the @oclif/test docs. - // Not sure how to get this working with type generics. - return captureOutput<string>(() => Command.run(args, oclifConfig), { testNodeEnv }).then(({ error, result }) => { - if (error) { - throw error; - } - return result; - }); - }; -} - -/** - * A lightweight wrapper around `@oclif/test`'s `runCommand` - * that loads our mock config and mock test env. - */ -export async function runCommandWithHooks(args?: string[]) { - const oclifConfig = await setupOclifConfig(); - return oclifRunCommand(args, oclifConfig, { testNodeEnv }); -} diff --git a/__tests__/helpers/vitest.matchers.ts b/__tests__/helpers/vitest.matchers.ts index c4883c226..1b367766c 100644 --- a/__tests__/helpers/vitest.matchers.ts +++ b/__tests__/helpers/vitest.matchers.ts @@ -4,13 +4,8 @@ import type { AnySchema } from 'ajv'; import betterAjvErrors from '@readme/better-ajv-errors'; import Ajv from 'ajv'; import jsYaml from 'js-yaml'; -import { expect } from 'vitest'; interface CustomMatchers<R = unknown> { - /** - * Ensures that the decoded Basic Auth header matches the expected API key. - */ - toBeBasicAuthApiKey(expectedApiKey: string): R; /** * Ensures that the expected YAML conforms to the given JSON Schema. */ @@ -23,25 +18,7 @@ declare module 'vitest' { interface AsymmetricMatchersContaining extends CustomMatchers {} } -function toBeBasicAuthApiKey(actualAuthorizationHeader: string, expectedApiKey: string): ExpectationResult { - const encodedApiKey = actualAuthorizationHeader.split(' ')[1]; - const decodedApiKey = Buffer.from(encodedApiKey, 'base64').toString().replace(/:$/, ''); - if (decodedApiKey !== expectedApiKey) { - return { - message: () => 'expected Basic Auth header to match API key', - pass: false, - actual: decodedApiKey, - expected: expectedApiKey, - }; - } - - return { - message: () => 'expected Basic Auth header to not match API key', - pass: true, - }; -} - -function toBeValidSchema( +export function toBeValidSchema( /** The input YAML, as a string */ yaml: string, /** The JSON schema file */ @@ -73,5 +50,3 @@ function toBeValidSchema( pass: true, }; } - -expect.extend({ toBeBasicAuthApiKey, toBeValidSchema }); diff --git a/__tests__/lib/createGHA.test.ts b/__tests__/lib/createGHA.test.ts index 130e3d0d0..1b8da6c7c 100644 --- a/__tests__/lib/createGHA.test.ts +++ b/__tests__/lib/createGHA.test.ts @@ -6,7 +6,7 @@ import type { Response } from 'simple-git'; import fs from 'node:fs'; import prompts from 'prompts'; -import { describe, beforeEach, afterEach, it, expect, vi, type MockInstance } from 'vitest'; +import { describe, beforeEach, afterEach, it, expect, vi, type MockInstance, beforeAll } from 'vitest'; import configstore from '../../src/lib/configstore.js'; import { getConfigStoreKey, getGHAFileName, git } from '../../src/lib/createGHA/index.js'; @@ -14,7 +14,8 @@ import { getMajorPkgVersion } from '../../src/lib/getPkgVersion.js'; import { after, before } from '../helpers/get-gha-setup.js'; import getGitRemoteMock from '../helpers/get-git-mock.js'; import ghaWorkflowSchema from '../helpers/github-workflow-schema.json' with { type: 'json' }; -import setupOclifConfig from '../helpers/setup-oclif-config.js'; +import { setupOclifConfig } from '../helpers/oclif.js'; +import { toBeValidSchema } from '../helpers/vitest.matchers.js'; const testWorkingDir = process.cwd(); @@ -27,6 +28,10 @@ describe('#createGHA', () => { let oclifConfig: Config; let yamlOutput; + beforeAll(() => { + expect.extend({ toBeValidSchema }); + }); + beforeEach(async () => { consoleInfoSpy = vi.spyOn(console, 'info').mockImplementation(() => {}); oclifConfig = await setupOclifConfig(); diff --git a/vitest.config.ts b/vitest.config.ts index 9f4dcb919..5d93478ff 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -6,6 +6,9 @@ export default defineConfig({ coverage: { exclude: [...coverageConfigDefaults.exclude, '**/dist-gha/**'], }, + // We'll defer to `@oclif/test` for console interception + // so we can run assertions against console output. + disableConsoleIntercept: true, env: { /** * The `chalk` and `colors` libraries have trouble with tests sometimes in test snapshots so @@ -19,6 +22,8 @@ export default defineConfig({ * tool in a testing environment. */ NODE_ENV: 'rdme-test', + // Node emits ExperimentalWarnings because we import JSON modules, so this hides that output. + NODE_OPTIONS: '--disable-warning=ExperimentalWarning', }, exclude: [ '**/__fixtures__/**', @@ -27,10 +32,5 @@ export default defineConfig({ '**/__snapshots__/**', ...configDefaults.exclude, ], - onConsoleLog(log: string, type: 'stderr' | 'stdout'): boolean | void { - // hides `rdme open` deprecation warning - return !(log.includes('`rdme open` is deprecated and will be removed in a future release') && type === 'stderr'); - }, - setupFiles: ['./__tests__/helpers/vitest.matchers.ts'], }, });