// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. import { compareSync } from 'dir-compare'; import * as Fs from 'fs-extra'; import * as Path from 'path'; import { ApiItemKind, ApiModel } from '@microsoft/api-extractor-model'; import { MarkdownDocumenter } from '../MarkdownDocumenter'; import { DocumenterConfig } from '../DocumenterConfig'; const configFilePath = Path.resolve(__dirname, "api-documenter.json"); const testTempDirPath = Path.resolve(__dirname, "test_temp"); // Relative to lib/documenters/test const snapshotsDirPath = Path.resolve(__dirname, '..', '..', '..', 'src', 'documenters', 'test', "snapshots"); // Simple integration test that compares the total output against an expected "snapshot" test('compare sample suite against expected', () => { const apiReportPath = Path.resolve(__dirname, "testData", "simple-suite-test.json"); const apiModel = new ApiModel(); apiModel.loadPackage(apiReportPath); const documenterConfig: DocumenterConfig = DocumenterConfig.loadFile(configFilePath); const markdownDocumenter = new MarkdownDocumenter(apiModel, documenterConfig); const outputDirPath = Path.resolve(testTempDirPath, "simple-suite-test"); const snapshotDirPath = Path.resolve(snapshotsDirPath, "simple-suite-test"); markdownDocumenter.generateFiles(outputDirPath); // TODO: There appears to be some un-awaited async code somewhere in the markdown documenter. // This timeout seems to be sufficient to wait for the process to complete before validating // its output. // But since the code is not annotated as being async, this should probably be considered a bug. setTimeout(() => {}, 1000); // Verify against expected contents const result = compareSync(outputDirPath, snapshotDirPath, { compareContent: true }); if(!result.same) { Fs.removeSync(snapshotDirPath); Fs.copySync(outputDirPath, snapshotDirPath); } // If this fails, then the docs build has generated new content. // View the diff in git and determine if the changes are appropriate or not. expect(result.same).toEqual(true); }); // We do not render individual pages for enums. Nor do we generate headings for enum members. // As such, links to individual enum members will instead point to the docs for the enum type, // on whatever page its definition is included. test('generates correct enum member link', () => { const apiReportPath = Path.resolve(__dirname, "testData", "enum-member-link-test.json"); const apiModel = new ApiModel(); apiModel.loadPackage(apiReportPath); const documenterConfig: DocumenterConfig = DocumenterConfig.loadFile(configFilePath); const markdownDocumenter = new MarkdownDocumenter(apiModel, documenterConfig); // package -> entry -> enum -> enum flag 1 const enumMember = apiModel.packages[0].members[0].members[0].members[0]; expect(enumMember.kind).toEqual(ApiItemKind.EnumMember); const result = markdownDocumenter._getLinkForApiItem(enumMember); expect(result).toEqual('/package#testenum-Enum'); }); // This is a repro of a bug where links to interface methods and links to class methods were being // generated differently. This test is intended to ensure consistency. test('class and interface method links are generated the same', () => { const apiReportPath = Path.resolve(__dirname, "testData", "method-link-consistency-test.json"); const apiModel = new ApiModel(); apiModel.loadPackage(apiReportPath); const documenterConfig: DocumenterConfig = DocumenterConfig.loadFile(configFilePath); const markdownDocumenter = new MarkdownDocumenter(apiModel, documenterConfig); const packageMembers = apiModel.packages[0].members[0].members; // Validate class method const classMember = packageMembers[0]; expect(classMember.kind).toEqual(ApiItemKind.Class); const classMethod = classMember.members[0]; expect(classMethod.kind).toEqual(ApiItemKind.Method); const classMethodRefId = markdownDocumenter._htmlIDForItem(classMethod); expect(classMethodRefId).toEqual('testclassmethod-Method'); const classMethodFilePath = markdownDocumenter._getFilePathForApiItem(classMethod); expect(classMethodFilePath).toEqual('api-extractor-playground/testclass.md'); const classMethodLink = markdownDocumenter._getLinkForApiItem(classMethod); expect(classMethodLink).toEqual('/api-extractor-playground/testclass#testclassmethod-Method'); // Validate interface method const interfaceMember = packageMembers[2]; expect(interfaceMember.kind).toEqual(ApiItemKind.Interface); const interfaceMethod = interfaceMember.members[0]; expect(interfaceMethod.kind).toEqual(ApiItemKind.MethodSignature); const interfaceMethodRefId = markdownDocumenter._htmlIDForItem(interfaceMethod); expect(interfaceMethodRefId).toEqual('testinterfacemethod-MethodSignature'); const interfaceMethodFilePath = markdownDocumenter._getFilePathForApiItem(interfaceMethod); expect(interfaceMethodFilePath).toEqual('api-extractor-playground/testinterface.md'); const interfaceMethodResult = markdownDocumenter._getLinkForApiItem(interfaceMethod); expect(interfaceMethodResult).toEqual('/api-extractor-playground/testinterface#testinterfacemethod-MethodSignature'); });