| import { beforeAll, describe, expect, test } from 'vitest' |
|
|
| import { get } from '@/tests/helpers/e2etest' |
|
|
| const makeURL = (pathname: string, apiVersion?: string): string => { |
| const params = new URLSearchParams({ pathname }) |
| if (apiVersion) { |
| params.set('apiVersion', apiVersion) |
| } |
| return `/api/article/body?${params}` |
| } |
|
|
| describe('REST transformer', () => { |
| beforeAll(() => { |
| if (!process.env.ROOT) { |
| console.warn( |
| 'WARNING: The REST transformer tests require the ROOT environment variable to be set to the fixture root', |
| ) |
| } |
| }) |
|
|
| test('REST page renders with markdown structure', async () => { |
| const res = await get(makeURL('/en/rest/actions/artifacts')) |
| expect(res.statusCode).toBe(200) |
| expect(res.headers['content-type']).toContain('text/markdown') |
|
|
| |
| expect(res.body).toContain('# GitHub Actions Artifacts') |
|
|
| |
| expect(res.body).toContain('Use the REST API to interact with artifacts in HubGit Actions.') |
|
|
| |
| expect(res.body).toContain('## About artifacts in HubGit Actions') |
| }) |
|
|
| test('REST operations are formatted correctly', async () => { |
| const res = await get(makeURL('/en/rest/actions/artifacts')) |
| expect(res.statusCode).toBe(200) |
|
|
| |
| expect(res.body).toContain('## List artifacts for a repository') |
|
|
| |
| expect(res.body).toContain('GET /repos/{owner}/{repo}/actions/artifacts') |
|
|
| |
| expect(res.body).toContain('Lists all artifacts for a repository.') |
| }) |
|
|
| test('Parameters section includes headers', async () => { |
| const res = await get(makeURL('/en/rest/actions/artifacts')) |
| expect(res.statusCode).toBe(200) |
|
|
| |
| expect(res.body).toContain('### Parameters') |
|
|
| |
| expect(res.body).toContain('#### Headers') |
|
|
| |
| expect(res.body).toContain('**`accept`** (string)') |
| expect(res.body).toContain('Setting to `application/vnd.github+json` is recommended.') |
| }) |
|
|
| test('Path and query parameters are listed', async () => { |
| const res = await get(makeURL('/en/rest/actions/artifacts')) |
| expect(res.statusCode).toBe(200) |
|
|
| |
| expect(res.body).toContain('#### Path and query parameters') |
|
|
| |
| expect(res.body).toContain('**`owner`** (string) (required)') |
| expect(res.body).toContain('The account owner of the repository.') |
|
|
| expect(res.body).toContain('**`repo`** (string) (required)') |
|
|
| expect(res.body).toContain('**`per_page`** (integer)') |
| expect(res.body).toContain('Default: `30`') |
| }) |
|
|
| test('Status codes are formatted correctly', async () => { |
| const res = await get(makeURL('/en/rest/actions/artifacts')) |
| expect(res.statusCode).toBe(200) |
|
|
| |
| expect(res.body).toContain('### HTTP response status codes') |
|
|
| |
| expect(res.body).toContain('**200**') |
| expect(res.body).toContain('OK') |
| }) |
|
|
| test('Code examples include curl with proper formatting', async () => { |
| const res = await get(makeURL('/en/rest/actions/artifacts')) |
| expect(res.statusCode).toBe(200) |
|
|
| |
| expect(res.body).toContain('### Code examples') |
|
|
| |
| expect(res.body).toContain('**Request:**') |
| expect(res.body).toContain('**Response schema:**') |
|
|
| |
| expect(res.body).toContain('```curl') |
| expect(res.body).toContain('curl -L \\') |
| expect(res.body).toContain('-X GET \\') |
| expect(res.body).toContain('https://api.github.com/repos/OWNER/REPO/actions/artifacts \\') |
| expect(res.body).toContain('-H "Accept: application/vnd.github.v3+json" \\') |
| expect(res.body).toContain('-H "Authorization: Bearer <YOUR-TOKEN>"') |
| }) |
|
|
| test('Code examples include X-GitHub-Api-Version header by default', async () => { |
| const res = await get(makeURL('/en/rest/actions/artifacts')) |
| expect(res.statusCode).toBe(200) |
|
|
| |
| expect(res.body).toContain('-H "X-GitHub-Api-Version: 2022-11-28"') |
| }) |
|
|
| test('Code examples include specified API version', async () => { |
| const res = await get(makeURL('/en/rest/actions/artifacts', '2022-11-28')) |
| expect(res.statusCode).toBe(200) |
|
|
| |
| expect(res.body).toContain('-H "X-GitHub-Api-Version: 2022-11-28"') |
| }) |
|
|
| test('Liquid tags are rendered in intro', async () => { |
| const res = await get(makeURL('/en/rest/actions/artifacts')) |
| expect(res.statusCode).toBe(200) |
|
|
| |
| expect(res.body).toContain('HubGit Actions') |
| expect(res.body).not.toContain('{% data variables.product.prodname_actions %}') |
|
|
| |
| expect(res.body).toMatch(/Use the REST API to interact with artifacts in HubGit Actions/) |
| expect(res.body).toMatch(/About artifacts in HubGit Actions/) |
| }) |
|
|
| test('AUTOTITLE links are resolved', async () => { |
| const res = await get(makeURL('/en/rest/actions/artifacts')) |
| expect(res.statusCode).toBe(200) |
|
|
| |
| |
| expect(res.body).toContain('[Storing workflow data as artifacts]') |
| expect(res.body).toContain('(/en/actions/using-workflows/storing-workflow-data-as-artifacts)') |
|
|
| |
| expect(res.body).not.toContain('[AUTOTITLE]') |
|
|
| |
| expect(res.body).toMatch( |
| /About artifacts in HubGit Actions[\s\S]*Storing workflow data as artifacts/, |
| ) |
| }) |
|
|
| test('Markdown links are preserved in descriptions', async () => { |
| const res = await get(makeURL('/en/rest/actions/artifacts')) |
| expect(res.statusCode).toBe(200) |
|
|
| |
| expect(res.body).toMatch(/\[.*?\]\(\/en\/.*?\)/) |
| }) |
|
|
| test('Response schema is formatted correctly', async () => { |
| const res = await get(makeURL('/en/rest/actions/artifacts')) |
| expect(res.statusCode).toBe(200) |
|
|
| |
| expect(res.body).toContain('**Response schema:**') |
| expect(res.body).toContain('```json') |
| expect(res.body).toContain('Status: 200') |
|
|
| |
| expect(res.body).toContain('"type":') |
| expect(res.body).toContain('"properties":') |
|
|
| |
| const schemaMatch = res.body.match(/```json\s+Status: 200\s+([\s\S]*?)```/) |
| expect(schemaMatch).toBeTruthy() |
|
|
| if (schemaMatch) { |
| const schemaContent = schemaMatch[1] |
| const schema = JSON.parse(schemaContent) |
|
|
| |
| expect(schema).toHaveProperty('type') |
| expect(schema.type).toBe('object') |
| expect(schema).toHaveProperty('properties') |
|
|
| |
| expect(schema.properties).toHaveProperty('total_count') |
| expect(schema.properties).toHaveProperty('artifacts') |
| } |
| }) |
|
|
| test('Non-REST pages return appropriate error', async () => { |
| const res = await get(makeURL('/en/get-started/start-your-journey/hello-world')) |
| expect(res.statusCode).toBe(200) |
|
|
| |
| expect(res.body).toContain('## Introduction') |
| }) |
|
|
| test('Invalid apiVersion returns 400 error', async () => { |
| |
| const res = await get(makeURL('/en/rest/actions/artifacts', 'invalid-version')) |
|
|
| |
| expect(res.statusCode).toBe(400) |
| const parsed = JSON.parse(res.body) |
| expect(parsed.error).toContain("Invalid apiVersion 'invalid-version'") |
| expect(parsed.error).toContain('Valid API versions are:') |
| expect(parsed.error).toContain('2022-11-28') |
| }) |
|
|
| test('Multiple apiVersion query parameters returns 400 error', async () => { |
| |
| const res = await get( |
| '/api/article/body?pathname=/en/rest/actions/artifacts&apiVersion=2022-11-28&apiVersion=2023-01-01', |
| ) |
|
|
| expect(res.statusCode).toBe(400) |
| const parsed = JSON.parse(res.body) |
| expect(parsed.error).toBe("Multiple 'apiVersion' keys") |
| }) |
|
|
| test('Valid apiVersion passes validation', async () => { |
| |
| const res = await get(makeURL('/en/rest/actions/artifacts', '2022-11-28')) |
|
|
| expect(res.statusCode).toBe(200) |
| expect(res.body).toContain('-H "X-GitHub-Api-Version: 2022-11-28"') |
| }) |
|
|
| test('Missing apiVersion defaults to latest', async () => { |
| |
| const res = await get(makeURL('/en/rest/actions/artifacts')) |
|
|
| expect(res.statusCode).toBe(200) |
| |
| expect(res.body).toContain('-H "X-GitHub-Api-Version: 2022-11-28"') |
| }) |
|
|
| test('Multiple operations on a page are all rendered', async () => { |
| const res = await get(makeURL('/en/rest/actions/artifacts')) |
| expect(res.statusCode).toBe(200) |
|
|
| |
| expect(res.body).toContain('## List artifacts for a repository') |
| expect(res.body).toContain('## Get an artifact') |
| expect(res.body).toContain('## Delete an artifact') |
| }) |
|
|
| test('Body parameters are formatted correctly for POST/PUT operations', async () => { |
| const res = await get(makeURL('/en/rest/actions/artifacts')) |
| expect(res.statusCode).toBe(200) |
|
|
| |
| |
| |
| }) |
|
|
| test('Content-type header is included for operations that need it', async () => { |
| const res = await get(makeURL('/en/rest/actions/artifacts')) |
| expect(res.statusCode).toBe(200) |
|
|
| |
| |
| }) |
|
|
| test('Non-English language paths work correctly', async () => { |
| |
| |
| const res = await get(makeURL('/ja/rest/actions/artifacts')) |
| expect(res.statusCode).toBe(200) |
|
|
| |
| |
| |
|
|
| |
| expect(res.body).toContain('## List artifacts for a repository') |
| expect(res.body).toContain('GET /repos/{owner}/{repo}/actions/artifacts') |
|
|
| |
| |
| |
| const hasJapaneseTitle = res.body.includes('# GitHub Actions アーティファクト') |
| const hasEnglishTitle = res.body.includes('# GitHub Actions Artifacts') |
|
|
| |
| expect(hasJapaneseTitle || hasEnglishTitle).toBe(true) |
|
|
| |
| if (hasJapaneseTitle) { |
| |
| expect(res.body).toContain('アーティファクト') |
| } else { |
| |
| expect(res.body).toContain('Use the REST API to interact with artifacts in HubGit Actions') |
| } |
| }) |
| }) |
|
|