Skip to content
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
18 changes: 18 additions & 0 deletions test/__fixtures__/no-component-schemas.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"openapi": "3.0.3",
"info": {
"title": "No component schemas",
"version": "1.0.0"
},
"paths": {
"/ping": {
"get": {
"responses": {
"200": {
"description": "ok"
}
}
}
}
}
}
71 changes: 71 additions & 0 deletions test/__fixtures__/resolve-schema-edges.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
{
"openapi": "3.0.3",
"info": {
"title": "Resolve schema edges",
"version": "1.0.0"
},
"paths": {
"/x": {
"get": {
"responses": {
"200": {
"description": "ok",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Pet"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"Pet": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"$ref": "#/components/schemas/Name"
}
}
},
"Name": {
"type": "string"
},
"Tags": {
"type": "array",
"items": {
"type": "string"
}
},
"Alias": {
"$ref": "#/components/schemas/Pet"
},
"Holder": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PetRef"
}
}
}
},
"PetRef": {
"type": "object",
"properties": {
"id": {
"type": "string"
}
}
}
}
}
}
148 changes: 147 additions & 1 deletion test/commands/changelogs/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import type { PageObject } from '../../helpers/page.types.js';

import fs from 'node:fs';
import fsPromises from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';

import chalk from 'chalk';
import grayMatter from 'gray-matter';
import { beforeAll, beforeEach, describe, expect, it } from 'vitest';
import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';

import Command from '../../../src/commands/changelogs.js';
import { APIv1Error } from '../../../src/lib/apiError.js';
Expand Down Expand Up @@ -42,6 +44,150 @@ describe('rdme changelogs', () => {
);
});

it('should rethrow filesystem errors other than a missing path', async () => {
const denied = Object.assign(new Error('permission denied'), { code: 'EACCES' });
vi.spyOn(fsPromises, 'stat').mockRejectedValue(denied);

await expect(run(['./test/__fixtures__/changelogs/new-docs', '--key', key])).rejects.toBe(denied);

vi.restoreAllMocks();
});

it('should upload child changelogs after their parentDocSlug target', async () => {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'rdme-changelogs-parent-'));
try {
fs.writeFileSync(
path.join(tmpDir, 'parent.md'),
`---
title: Parent changelog
---
Parent body
`,
);
fs.writeFileSync(
path.join(tmpDir, 'child.md'),
`---
title: Child changelog
parentDocSlug: parent
---
Child body
`,
);

const getMocks = getAPIv1Mock()
.get('/api/v1/changelogs/parent')
.basicAuth({ user: key })
.reply(404, { error: 'CHANGELOG_NOTFOUND' })
.get('/api/v1/changelogs/child')
.basicAuth({ user: key })
.reply(404, { error: 'CHANGELOG_NOTFOUND' });

const postMocks = getAPIv1Mock()
.post('/api/v1/changelogs', body => body.slug === 'parent')
.basicAuth({ user: key })
.reply(201, { slug: 'parent', _id: '1' })
.post('/api/v1/changelogs', body => body.slug === 'child')
.basicAuth({ user: key })
.reply(201, { slug: 'child', _id: '2' });

const result = await run([tmpDir, '--key', key]);

expect(result).toContain("successfully created 'parent'");
expect(result).toContain("successfully created 'child'");
expect(result.indexOf("successfully created 'parent'")).toBeLessThan(
result.indexOf("successfully created 'child'"),
);

getMocks.done();
postMocks.done();
} finally {
fs.rmSync(tmpDir, { recursive: true, force: true });
}
});

it('should sort changelogs that use the legacy parentDoc attribute', async () => {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'rdme-changelogs-parentdoc-'));
try {
fs.writeFileSync(
path.join(tmpDir, 'child.md'),
`---
title: Child changelog
parentDoc: 5f92cbf10cf217478ba93561
---
Child body
`,
);
fs.writeFileSync(
path.join(tmpDir, 'parent.md'),
`---
title: Parent changelog
---
Parent body
`,
);

const getMocks = getAPIv1Mock()
.get('/api/v1/changelogs/parent')
.basicAuth({ user: key })
.reply(404, { error: 'CHANGELOG_NOTFOUND' })
.get('/api/v1/changelogs/child')
.basicAuth({ user: key })
.reply(404, { error: 'CHANGELOG_NOTFOUND' });

const postMocks = getAPIv1Mock()
.post('/api/v1/changelogs', body => body.slug === 'parent')
.basicAuth({ user: key })
.reply(201, { slug: 'parent', _id: '1' })
.post('/api/v1/changelogs', body => body.slug === 'child')
.basicAuth({ user: key })
.reply(201, { slug: 'child', _id: '2' });

const result = await run([tmpDir, '--key', key]);

expect(result).toContain("successfully created 'parent'");
expect(result).toContain("successfully created 'child'");

getMocks.done();
postMocks.done();
} finally {
fs.rmSync(tmpDir, { recursive: true, force: true });
}
});

it('should error when parentDocSlug values form a cycle', async () => {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'rdme-changelogs-cycle-'));
try {
fs.writeFileSync(
path.join(tmpDir, 'a.md'),
`---
title: A
parentDocSlug: b
---
A
`,
);
fs.writeFileSync(
path.join(tmpDir, 'b.md'),
`---
title: B
parentDocSlug: a
---
B
`,
);

await expect(run([tmpDir, '--key', key])).rejects.toThrow(/Cyclic dependency/);
} finally {
fs.rmSync(tmpDir, { recursive: true, force: true });
}
});

describe('existing changelogs', () => {
let simpleDoc: PageObject;
let anotherDoc: PageObject;
Expand Down
Loading
Loading