Skip to content

test: add comprehensive document and collection command tests#24

Open
gnapse wants to merge 3 commits intomainfrom
test/expand-coverage
Open

test: add comprehensive document and collection command tests#24
gnapse wants to merge 3 commits intomainfrom
test/expand-coverage

Conversation

@gnapse
Copy link
Collaborator

@gnapse gnapse commented Jan 26, 2026

Summary

Adds dedicated test files for the two priority command modules per #13.

New Test Files

document.test.ts (21 tests)

  • list: default options, pagination, sorting, collection filter, JSON/NDJSON output
  • get: URL ID resolution, raw markdown output, JSON output
  • open: browser opening
  • create: title + collection, text content, publish flag, JSON output
  • update: title, text, markdown heading extraction
  • delete: confirmation requirement, deletion
  • move: collection transfer
  • archive/unarchive: document archiving

collection.test.ts (18 tests)

  • list: default options, pagination, JSON/NDJSON output, full fields
  • get: ID lookup, JSON output
  • create: name, description, color, private flag, JSON output
  • update: name, description, color, JSON output
  • delete: confirmation requirement, deletion

Test Count

Before After
59 tests 98 tests

Notes

Tests use proper UUID format for entity IDs to correctly exercise the resolution logic. Mock sequences handle the collection/document verification calls that happen during resolution.

Addresses #13

Ubuntu added 2 commits January 26, 2026 02:09
Adds dedicated test files for:
- document.test.ts (21 tests): list, get, open, create, update, delete, move, archive, unarchive
- collection.test.ts (18 tests): list, get, create, update, delete

Tests cover:
- All CLI options (--json, --ndjson, --full, pagination, sorting)
- API request parameters validation
- Confirmation requirements for destructive operations
- Collection/document resolution

Addresses #13
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR significantly expands test coverage for the Outline CLI by adding four comprehensive test files for core command modules. The tests follow established vitest patterns with proper mocking, test isolation, and cover various output formats (JSON, NDJSON, formatted).

Changes:

  • Adds 21 tests for document commands (list, get, open, create, update, delete, move, archive, unarchive)
  • Adds 18 tests for collection commands (list, get, create, update, delete)
  • Adds 4 tests for search command functionality
  • Adds 5 tests for skill management commands

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/tests/document.test.ts Comprehensive CRUD tests for document operations including ID resolution, markdown handling, and confirmation flows
src/tests/collection.test.ts Full test coverage for collection management with pagination, output formats, and delete confirmations
src/tests/search.test.ts Tests for document search with filters, status options, and various output formats
src/tests/skill.test.ts Tests for skill installer operations including list, install, uninstall, and error handling

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +298 to +427
describe("document create", () => {
it("creates document with title and collection ID", async () => {
// First call: resolveCollectionId verifies collection exists
// Second call: documents.create
apiRequest
.mockResolvedValueOnce({
data: { id: COL_ID, name: "Test Collection" },
})
.mockResolvedValueOnce({ data: mockDocument });

const { registerDocumentCommand } = await import(
"../commands/document.js"
);
const program = new Command();
program.exitOverride();
registerDocumentCommand(program);

await program.parseAsync([
"node",
"ol",
"document",
"create",
"--title",
"New Doc",
"--collection",
COL_ID,
]);

expect(apiRequest).toHaveBeenLastCalledWith("documents.create", {
title: "New Doc",
collectionId: COL_ID,
});
expect(logs[0]).toContain("Created:");
});

it("creates document with text content", async () => {
apiRequest
.mockResolvedValueOnce({
data: { id: COL_ID, name: "Test Collection" },
})
.mockResolvedValueOnce({ data: mockDocument });

const { registerDocumentCommand } = await import(
"../commands/document.js"
);
const program = new Command();
program.exitOverride();
registerDocumentCommand(program);

await program.parseAsync([
"node",
"ol",
"document",
"create",
"--title",
"New Doc",
"--collection",
COL_ID,
"--text",
"Hello world",
]);

expect(apiRequest).toHaveBeenLastCalledWith("documents.create", {
title: "New Doc",
collectionId: COL_ID,
text: "Hello world",
});
});

it("creates document with --publish flag", async () => {
apiRequest
.mockResolvedValueOnce({
data: { id: COL_ID, name: "Test Collection" },
})
.mockResolvedValueOnce({ data: mockDocument });

const { registerDocumentCommand } = await import(
"../commands/document.js"
);
const program = new Command();
program.exitOverride();
registerDocumentCommand(program);

await program.parseAsync([
"node",
"ol",
"document",
"create",
"--title",
"New Doc",
"--collection",
COL_ID,
"--publish",
]);

expect(apiRequest).toHaveBeenLastCalledWith("documents.create", {
title: "New Doc",
collectionId: COL_ID,
publish: true,
});
});

it("outputs JSON when --json flag used", async () => {
apiRequest.mockResolvedValue({
data: mockDocument,
});

const { registerDocumentCommand } = await import(
"../commands/document.js"
);
const program = new Command();
program.exitOverride();
registerDocumentCommand(program);

await program.parseAsync([
"node",
"ol",
"document",
"create",
"--title",
"New Doc",
"--collection",
COL_ID,
"--json",
]);

const parsed = JSON.parse(logs[0]);
expect(parsed.title).toBe("Test Document");
});
});
Copy link

Copilot AI Jan 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The document create and update commands support a --file option to read markdown from a file (see lines 58-59 and 164 in src/commands/document.ts), but there are no test cases verifying this functionality. Consider adding tests for creating and updating documents using the --file option to ensure this feature is properly covered.

Copilot uses AI. Check for mistakes.
Comment on lines +59 to +188
describe("document list", () => {
it("lists documents with default options", async () => {
apiRequest.mockResolvedValue({
data: [mockDocument],
pagination: { offset: 0, limit: 25 },
});

const { registerDocumentCommand } = await import(
"../commands/document.js"
);
const program = new Command();
program.exitOverride();
registerDocumentCommand(program);

await program.parseAsync(["node", "ol", "document", "list"]);

expect(apiRequest).toHaveBeenCalledWith("documents.list", {
limit: 25,
offset: 0,
sort: "updatedAt",
direction: "DESC",
});
});

it("passes pagination options", async () => {
apiRequest.mockResolvedValue({
data: [],
pagination: { offset: 10, limit: 5 },
});

const { registerDocumentCommand } = await import(
"../commands/document.js"
);
const program = new Command();
program.exitOverride();
registerDocumentCommand(program);

await program.parseAsync([
"node",
"ol",
"document",
"list",
"--limit",
"5",
"--offset",
"10",
]);

expect(apiRequest).toHaveBeenCalledWith("documents.list", {
limit: 5,
offset: 10,
sort: "updatedAt",
direction: "DESC",
});
});

it("passes sort options", async () => {
apiRequest.mockResolvedValue({
data: [],
pagination: { offset: 0, limit: 25 },
});

const { registerDocumentCommand } = await import(
"../commands/document.js"
);
const program = new Command();
program.exitOverride();
registerDocumentCommand(program);

await program.parseAsync([
"node",
"ol",
"document",
"list",
"--sort",
"title",
"--direction",
"ASC",
]);

expect(apiRequest).toHaveBeenCalledWith("documents.list", {
limit: 25,
offset: 0,
sort: "title",
direction: "ASC",
});
});

it("outputs JSON when --json flag used", async () => {
apiRequest.mockResolvedValue({
data: [mockDocument],
pagination: { offset: 0, limit: 25 },
});

const { registerDocumentCommand } = await import(
"../commands/document.js"
);
const program = new Command();
program.exitOverride();
registerDocumentCommand(program);

await program.parseAsync(["node", "ol", "document", "list", "--json"]);

const parsed = JSON.parse(logs[0]);
expect(parsed[0].title).toBe("Test Document");
});

it("outputs NDJSON when --ndjson flag used", async () => {
apiRequest.mockResolvedValue({
data: [
mockDocument,
{ ...mockDocument, id: "doc-456", title: "Second" },
],
pagination: { offset: 0, limit: 25 },
});

const { registerDocumentCommand } = await import(
"../commands/document.js"
);
const program = new Command();
program.exitOverride();
registerDocumentCommand(program);

await program.parseAsync(["node", "ol", "document", "list", "--ndjson"]);

expect(logs.length).toBe(2);
expect(JSON.parse(logs[0]).title).toBe("Test Document");
expect(JSON.parse(logs[1]).title).toBe("Second");
});
});
Copy link

Copilot AI Jan 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description mentions "collection filter" as one of the tested features for document list, but there's no test case verifying that the collection filter is properly passed to the API. Consider adding a test that verifies when the --collection option is used with document list, the collectionId is correctly resolved and passed to the documents.list API call (similar to lines 102-104 in src/commands/document.ts).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants