2020-04-08 14:13:33 +05:30
# frozen_string_literal: true
2021-09-04 01:27:46 +05:30
require_relative '../../../../tooling/graphql/docs/renderer'
2020-04-08 14:13:33 +05:30
2021-09-04 01:27:46 +05:30
RSpec . describe Tooling :: Graphql :: Docs :: Renderer do
2020-04-08 14:13:33 +05:30
describe '#contents' do
2021-06-08 01:23:25 +05:30
shared_examples 'renders correctly as GraphQL documentation' do
it 'contains the expected section' do
# duplicative - but much better error messages!
section . lines . each { | line | expect ( contents ) . to include ( line ) }
expect ( contents ) . to include ( section )
end
end
2021-09-04 01:27:46 +05:30
let ( :template ) { Rails . root . join ( 'tooling/graphql/docs/templates/default.md.haml' ) }
2021-06-08 01:23:25 +05:30
let ( :field_description ) { 'List of objects.' }
2021-10-27 15:23:28 +05:30
let ( :type ) { :: GraphQL :: Types :: Int }
2020-04-08 14:13:33 +05:30
2021-04-29 21:17:54 +05:30
let ( :query_type ) do
Class . new ( Types :: BaseObject ) { graphql_name 'Query' } . tap do | t |
# this keeps type and field_description in scope.
t . field :foo , type , null : true , description : field_description do
2021-10-27 15:23:28 +05:30
argument :id , GraphQL :: Types :: ID , required : false , description : 'ID of the object.'
2021-04-17 20:07:23 +05:30
end
2020-04-08 14:13:33 +05:30
end
2021-04-29 21:17:54 +05:30
end
2020-04-08 14:13:33 +05:30
2021-06-08 01:23:25 +05:30
let ( :mutation_root ) do
Class . new ( :: Types :: BaseObject ) do
include :: Gitlab :: Graphql :: MountMutation
graphql_name 'Mutation'
end
end
2021-04-29 21:17:54 +05:30
let ( :mock_schema ) do
Class . new ( GraphQL :: Schema ) do
def resolve_type ( obj , ctx )
raise 'Not a real schema'
end
end
2020-04-08 14:13:33 +05:30
end
subject ( :contents ) do
2021-04-29 21:17:54 +05:30
mock_schema . query ( query_type )
2021-06-08 01:23:25 +05:30
mock_schema . mutation ( mutation_root ) if mutation_root . fields . any?
2021-04-29 21:17:54 +05:30
2020-04-08 14:13:33 +05:30
described_class . new (
2021-04-29 21:17:54 +05:30
mock_schema ,
2020-04-08 14:13:33 +05:30
output_dir : nil ,
template : template
) . contents
end
2021-04-17 20:07:23 +05:30
describe 'headings' do
it 'contains the expected sections' do
expect ( contents . lines . map ( & :chomp ) ) . to include (
'## `Query` type' ,
2021-06-08 01:23:25 +05:30
'## `Mutation` type' ,
'## Connections' ,
2021-04-17 20:07:23 +05:30
'## Object types' ,
'## Enumeration types' ,
'## Scalar types' ,
'## Abstract types' ,
'### Unions' ,
2021-06-08 01:23:25 +05:30
'### Interfaces' ,
'## Input types'
2021-04-17 20:07:23 +05:30
)
end
end
context 'when a field has a list type' do
2020-04-08 14:13:33 +05:30
let ( :type ) do
2020-04-22 19:07:51 +05:30
Class . new ( Types :: BaseObject ) do
2020-04-08 14:13:33 +05:30
graphql_name 'ArrayTest'
2021-10-27 15:23:28 +05:30
field :foo , [ GraphQL :: Types :: String ] , null : false , description : 'A description.'
2020-04-08 14:13:33 +05:30
end
end
specify do
2021-04-17 20:07:23 +05:30
type_name = '[String!]!'
inner_type = 'string'
2020-04-08 14:13:33 +05:30
expectation = << ~ DOC
2021-04-17 20:07:23 +05:30
### `ArrayTest`
2020-04-08 14:13:33 +05:30
2021-06-08 01:23:25 +05:30
#### Fields
| Name | Type | Description |
| - - - - | - - - - | - - - - - - - - - - - |
| < a id = " arraytestfoo " > < / a>`foo` | [` #{ type_name } `]( # #{ inner_type } ) | A description. |
2020-04-08 14:13:33 +05:30
DOC
is_expected . to include ( expectation )
end
2021-04-17 20:07:23 +05:30
describe 'a top level query field' do
let ( :expectation ) do
<< ~ DOC
2021-06-08 01:23:25 +05:30
### `Query.foo`
2021-04-17 20:07:23 +05:30
List of objects .
Returns [ ` ArrayTest ` ] ( #arraytest).
#### Arguments
| Name | Type | Description |
| - - - - | - - - - | - - - - - - - - - - - |
2021-06-08 01:23:25 +05:30
| < a id = " queryfooid " > < / a>`id` | [`ID`]( # id) | ID of the object. |
2021-04-17 20:07:23 +05:30
DOC
end
it 'generates the query with arguments' do
expect ( subject ) . to include ( expectation )
end
context 'when description does not end with `.`' do
let ( :field_description ) { 'List of objects' }
it 'adds the `.` to the end' do
expect ( subject ) . to include ( expectation )
end
end
end
2020-04-08 14:13:33 +05:30
end
2021-04-17 20:07:23 +05:30
describe 'when fields are not defined in alphabetical order' do
2020-04-08 14:13:33 +05:30
let ( :type ) do
2020-04-22 19:07:51 +05:30
Class . new ( Types :: BaseObject ) do
2020-04-08 14:13:33 +05:30
graphql_name 'OrderingTest'
2021-10-27 15:23:28 +05:30
field :foo , GraphQL :: Types :: String , null : false , description : 'A description of foo field.'
field :bar , GraphQL :: Types :: String , null : false , description : 'A description of bar field.'
2020-04-08 14:13:33 +05:30
end
end
2021-04-17 20:07:23 +05:30
it 'lists the fields in alphabetical order' do
2020-04-08 14:13:33 +05:30
expectation = << ~ DOC
2021-04-17 20:07:23 +05:30
### `OrderingTest`
2020-04-08 14:13:33 +05:30
2021-06-08 01:23:25 +05:30
#### Fields
| Name | Type | Description |
| - - - - | - - - - | - - - - - - - - - - - |
| < a id = " orderingtestbar " > < / a>`bar` | [`String!`]( # string) | A description of bar field. |
| < a id = " orderingtestfoo " > < / a>`foo` | [`String!`]( # string) | A description of foo field. |
2020-04-08 14:13:33 +05:30
DOC
is_expected . to include ( expectation )
end
end
2021-06-08 01:23:25 +05:30
context 'when a field has a documentation reference' do
let ( :type ) do
wibble = Class . new ( :: Types :: BaseObject ) do
graphql_name 'Wibble'
2021-10-27 15:23:28 +05:30
field :x , :: GraphQL :: Types :: Int , null : false
2021-06-08 01:23:25 +05:30
end
Class . new ( Types :: BaseObject ) do
graphql_name 'DocRefSpec'
description 'Testing doc refs'
field :foo ,
2021-10-27 15:23:28 +05:30
type : GraphQL :: Types :: String ,
2021-06-08 01:23:25 +05:30
null : false ,
description : 'The foo.' ,
see : { 'A list of foos' = > 'https://example.com/foos' }
field :bar ,
2021-10-27 15:23:28 +05:30
type : GraphQL :: Types :: String ,
2021-06-08 01:23:25 +05:30
null : false ,
description : 'The bar.' ,
see : { 'A list of bars' = > 'https://example.com/bars' } do
2021-10-27 15:23:28 +05:30
argument :barity , :: GraphQL :: Types :: Int , required : false , description : '?'
2021-06-08 01:23:25 +05:30
end
field :wibbles ,
type : wibble . connection_type ,
null : true ,
description : 'The wibbles' ,
see : { 'wibblance' = > 'https://example.com/wibbles' }
end
end
let ( :section ) do
<< ~ DOC
### `DocRefSpec`
Testing doc refs .
#### Fields
| Name | Type | Description |
| - - - - | - - - - | - - - - - - - - - - - |
| < a id = " docrefspecfoo " > < / a>`foo` | [`String!`]( # string) | The foo. See [A list of foos](https: / / example . com / foos ) . |
| < a id = " docrefspecwibbles " > < / a>`wibbles` | [`WibbleConnection`]( # wibbleconnection) | The wibbles. See [wibblance](https: / / example . com / wibbles ) . ( see [ Connections ] ( #connections)) |
#### Fields with arguments
##### `DocRefSpec.bar`
The bar . See [ A list of bars ] ( https : / /ex ample . com / bars ) .
Returns [ ` String! ` ] ( #string).
###### Arguments
| Name | Type | Description |
| - - - - | - - - - | - - - - - - - - - - - |
| < a id = " docrefspecbarbarity " > < / a>`barity` | [`Int`]( # int) | ?. |
DOC
end
it_behaves_like 'renders correctly as GraphQL documentation'
end
context 'when an argument is deprecated' do
let ( :type ) do
Class . new ( Types :: BaseObject ) do
graphql_name 'DeprecatedTest'
description 'A thing we used to use, but no longer support'
field :foo ,
2021-10-27 15:23:28 +05:30
type : GraphQL :: Types :: String ,
2021-06-08 01:23:25 +05:30
null : false ,
description : 'A description.' do
2021-10-27 15:23:28 +05:30
argument :foo_arg , GraphQL :: Types :: String ,
2021-06-08 01:23:25 +05:30
required : false ,
description : 'The argument.' ,
deprecated : { reason : 'Bad argument' , milestone : '101.2' }
end
end
end
let ( :section ) do
<< ~ DOC
##### `DeprecatedTest.foo`
A description .
Returns [ ` String! ` ] ( #string).
###### Arguments
| Name | Type | Description |
| - - - - | - - - - | - - - - - - - - - - - |
| < a id = " deprecatedtestfoofooarg " > < / a>`fooArg` **{warning-solid}** | [`String`]( # string) | **Deprecated** in 101.2. Bad argument. |
DOC
end
it_behaves_like 'renders correctly as GraphQL documentation'
end
2021-04-17 20:07:23 +05:30
context 'when a field is deprecated' do
2020-04-08 14:13:33 +05:30
let ( :type ) do
2020-04-22 19:07:51 +05:30
Class . new ( Types :: BaseObject ) do
2020-04-08 14:13:33 +05:30
graphql_name 'DeprecatedTest'
2021-06-08 01:23:25 +05:30
description 'A thing we used to use, but no longer support'
2020-04-08 14:13:33 +05:30
2021-04-17 20:07:23 +05:30
field :foo ,
2021-10-27 15:23:28 +05:30
type : GraphQL :: Types :: String ,
2021-04-17 20:07:23 +05:30
null : false ,
deprecated : { reason : 'This is deprecated' , milestone : '1.10' } ,
description : 'A description.'
2021-04-29 21:17:54 +05:30
field :foo_with_args ,
2021-10-27 15:23:28 +05:30
type : GraphQL :: Types :: String ,
2021-04-29 21:17:54 +05:30
null : false ,
2021-06-08 01:23:25 +05:30
deprecated : { reason : 'Do not use' , milestone : '1.10' , replacement : 'X.y' } ,
2021-04-29 21:17:54 +05:30
description : 'A description.' do
2021-10-27 15:23:28 +05:30
argument :arg , GraphQL :: Types :: Int , required : false , description : 'Argity'
2021-04-29 21:17:54 +05:30
end
field :bar ,
2021-10-27 15:23:28 +05:30
type : GraphQL :: Types :: String ,
2021-04-29 21:17:54 +05:30
null : false ,
description : 'A description.' ,
deprecated : {
reason : :renamed ,
milestone : '1.10' ,
replacement : 'Query.boom'
}
2020-04-08 14:13:33 +05:30
end
end
2021-06-08 01:23:25 +05:30
let ( :section ) do
<< ~ DOC
2021-04-17 20:07:23 +05:30
### `DeprecatedTest`
2020-04-08 14:13:33 +05:30
2021-06-08 01:23:25 +05:30
A thing we used to use , but no longer support .
2021-04-29 21:17:54 +05:30
2021-06-08 01:23:25 +05:30
#### Fields
| Name | Type | Description |
| - - - - | - - - - | - - - - - - - - - - - |
| < a id = " deprecatedtestbar " > < / a>`bar` **{warning-solid}** | [`String!`]( # string) | **Deprecated** in 1.10. This was renamed. Use: [`Query.boom`]( # queryboom). |
| < a id = " deprecatedtestfoo " > < / a>`foo` **{warning-solid}** | [`String!`]( # string) | **Deprecated** in 1.10. This is deprecated. |
#### Fields with arguments
##### `DeprecatedTest.fooWithArgs`
A description .
WARNING :
** Deprecated ** in 1 . 10 .
Do not use .
Use : [ ` X.y ` ] ( #xy).
Returns [ ` String! ` ] ( #string).
###### Arguments
| Name | Type | Description |
| - - - - | - - - - | - - - - - - - - - - - |
| < a id = " deprecatedtestfoowithargsarg " > < / a>`arg` | [`Int`]( # int) | Argity. |
DOC
2021-04-29 21:17:54 +05:30
end
2021-06-08 01:23:25 +05:30
it_behaves_like 'renders correctly as GraphQL documentation'
2021-04-29 21:17:54 +05:30
end
context 'when a Query.field is deprecated' do
before do
query_type . field (
name : :bar ,
type : type ,
null : true ,
description : 'A bar' ,
deprecated : { reason : :renamed , milestone : '10.11' , replacement : 'Query.foo' }
)
end
2021-10-27 15:23:28 +05:30
let ( :type ) { :: GraphQL :: Types :: Int }
2021-06-08 01:23:25 +05:30
let ( :section ) do
<< ~ DOC
### `Query.bar`
2021-04-29 21:17:54 +05:30
A bar .
WARNING :
** Deprecated ** in 10 . 11 .
This was renamed .
2021-06-08 01:23:25 +05:30
Use : [ ` Query.foo ` ] ( #queryfoo).
2021-04-29 21:17:54 +05:30
Returns [ ` Int ` ] ( #int).
2020-04-08 14:13:33 +05:30
DOC
end
2021-06-08 01:23:25 +05:30
it_behaves_like 'renders correctly as GraphQL documentation'
2020-04-08 14:13:33 +05:30
end
2020-11-24 15:15:51 +05:30
2021-04-17 20:07:23 +05:30
context 'when a field has an Enumeration type' do
2020-11-24 15:15:51 +05:30
let ( :type ) do
enum_type = Class . new ( Types :: BaseEnum ) do
graphql_name 'MyEnum'
2021-06-08 01:23:25 +05:30
description 'A test of an enum.'
2020-11-24 15:15:51 +05:30
2021-04-17 20:07:23 +05:30
value 'BAZ' ,
description : 'A description of BAZ.'
value 'BAR' ,
description : 'A description of BAR.' ,
deprecated : { reason : 'This is deprecated' , milestone : '1.10' }
2021-09-04 01:27:46 +05:30
value 'BOOP' ,
description : 'A description of BOOP.' ,
deprecated : { reason : :renamed , replacement : 'MyEnum.BAR' , milestone : '1.10' }
2020-11-24 15:15:51 +05:30
end
Class . new ( Types :: BaseObject ) do
graphql_name 'EnumTest'
2021-02-22 17:27:13 +05:30
field :foo , enum_type , null : false , description : 'A description of foo field.'
2020-11-24 15:15:51 +05:30
end
end
2021-06-08 01:23:25 +05:30
let ( :section ) do
<< ~ DOC
2021-04-17 20:07:23 +05:30
### `MyEnum`
2020-11-24 15:15:51 +05:30
2021-06-08 01:23:25 +05:30
A test of an enum .
2020-11-24 15:15:51 +05:30
| Value | Description |
| - - - - - | - - - - - - - - - - - |
2021-09-04 01:27:46 +05:30
| < a id = " myenumbar " > < / a>`BAR` **{warning-solid}** | **Deprecated** in 1.10. This is deprecated. |
2021-06-08 01:23:25 +05:30
| < a id = " myenumbaz " > < / a>`BAZ` | A description of BAZ. |
2021-09-04 01:27:46 +05:30
| < a id = " myenumboop " > < / a>`BOOP` **{warning-solid}** | **Deprecated** in 1.10. This was renamed. Use: [`MyEnum.BAR`]( # myenumbar). |
2020-11-24 15:15:51 +05:30
DOC
end
2021-06-08 01:23:25 +05:30
it_behaves_like 'renders correctly as GraphQL documentation'
2020-11-24 15:15:51 +05:30
end
2021-04-17 20:07:23 +05:30
context 'when a field has a global ID type' do
let ( :type ) do
Class . new ( Types :: BaseObject ) do
graphql_name 'IDTest'
description 'A test for rendering IDs.'
field :foo , :: Types :: GlobalIDType [ :: User ] , null : true , description : 'A user foo.'
end
end
2021-06-08 01:23:25 +05:30
describe 'section for IDTest' do
let ( :section ) do
<< ~ DOC
### `IDTest`
2021-04-17 20:07:23 +05:30
2021-06-08 01:23:25 +05:30
A test for rendering IDs .
2021-04-17 20:07:23 +05:30
2021-06-08 01:23:25 +05:30
#### Fields
2021-04-17 20:07:23 +05:30
2021-06-08 01:23:25 +05:30
| Name | Type | Description |
| - - - - | - - - - | - - - - - - - - - - - |
| < a id = " idtestfoo " > < / a>`foo` | [`UserID`]( # userid) | A user foo. |
DOC
end
2021-04-17 20:07:23 +05:30
2021-06-08 01:23:25 +05:30
it_behaves_like 'renders correctly as GraphQL documentation'
end
2021-04-17 20:07:23 +05:30
2021-06-08 01:23:25 +05:30
describe 'section for UserID' do
let ( :section ) do
<< ~ DOC
### `UserID`
A ` UserID ` is a global ID . It is encoded as a string .
An example ` UserID ` is : ` "gid://gitlab/User/1" ` .
DOC
end
2021-04-17 20:07:23 +05:30
2021-06-08 01:23:25 +05:30
it_behaves_like 'renders correctly as GraphQL documentation'
2021-04-17 20:07:23 +05:30
end
end
2021-06-08 01:23:25 +05:30
context 'when there is a mutation' do
let ( :mutation ) do
mutation = Class . new ( :: Mutations :: BaseMutation )
mutation . graphql_name 'MakeItPretty'
mutation . description 'Make everything very pretty.'
mutation . argument :prettiness_factor ,
2022-01-26 12:08:38 +05:30
type : GraphQL :: Types :: Float ,
2021-06-08 01:23:25 +05:30
required : true ,
description : 'How much prettier?'
mutation . argument :pulchritude ,
2022-01-26 12:08:38 +05:30
type : GraphQL :: Types :: Float ,
2021-06-08 01:23:25 +05:30
required : false ,
description : 'How much prettier?' ,
deprecated : {
reason : :renamed ,
replacement : 'prettinessFactor' ,
milestone : '72.34'
}
mutation . field :everything ,
2021-10-27 15:23:28 +05:30
type : GraphQL :: Types :: String ,
2021-06-08 01:23:25 +05:30
null : true ,
description : 'What we made prettier.'
mutation . field :omnis ,
2021-10-27 15:23:28 +05:30
type : GraphQL :: Types :: String ,
2021-06-08 01:23:25 +05:30
null : true ,
description : 'What we made prettier.' ,
deprecated : {
reason : :renamed ,
replacement : 'everything' ,
milestone : '72.34'
}
mutation
end
before do
mutation_root . mount_mutation mutation
end
it_behaves_like 'renders correctly as GraphQL documentation' do
let ( :section ) do
<< ~ DOC
### `Mutation.makeItPretty`
Make everything very pretty .
Input type : ` MakeItPrettyInput `
#### Arguments
| Name | Type | Description |
| - - - - | - - - - | - - - - - - - - - - - |
| < a id = " mutationmakeitprettyclientmutationid " > < / a>`clientMutationId` | [`String`]( # string) | A unique identifier for the client performing the mutation. |
| < a id = " mutationmakeitprettyprettinessfactor " > < / a>`prettinessFactor` | [`Float!`]( # float) | How much prettier?. |
| < a id = " mutationmakeitprettypulchritude " > < / a>`pulchritude` **{warning-solid}** | [`Float`]( # float) | **Deprecated:** This was renamed. Please use `prettinessFactor`. Deprecated in 72.34. |
#### Fields
| Name | Type | Description |
| - - - - | - - - - | - - - - - - - - - - - |
| < a id = " mutationmakeitprettyclientmutationid " > < / a>`clientMutationId` | [`String`]( # string) | A unique identifier for the client performing the mutation. |
| < a id = " mutationmakeitprettyerrors " > < / a>`errors` | [`[String!]!`]( # string) | Errors encountered during execution of the mutation. |
| < a id = " mutationmakeitprettyeverything " > < / a>`everything` | [`String`]( # string) | What we made prettier. |
| < a id = " mutationmakeitprettyomnis " > < / a>`omnis` **{warning-solid}** | [`String`]( # string) | **Deprecated:** This was renamed. Please use `everything`. Deprecated in 72.34. |
DOC
end
end
it 'does not render the automatically generated payload type' do
expect ( contents ) . not_to include ( 'MakeItPrettyPayload' )
end
it 'does not render the automatically generated input type as its own section' do
expect ( contents ) . not_to include ( '# `MakeItPrettyInput`' )
end
end
context 'when there is an input type' do
let ( :type ) do
Class . new ( :: Types :: BaseObject ) do
graphql_name 'Foo'
2021-10-27 15:23:28 +05:30
field :wibble , type : :: GraphQL :: Types :: Int , null : true do
2021-06-08 01:23:25 +05:30
argument :date_range ,
type : :: Types :: TimeframeInputType ,
required : true ,
description : 'When the foo happened.'
end
end
end
let ( :section ) do
<< ~ DOC
### `Timeframe`
A time - frame defined as a closed inclusive range of two dates .
#### Arguments
| Name | Type | Description |
| - - - - | - - - - | - - - - - - - - - - - |
2021-11-11 11:23:49 +05:30
| < a id = " timeframeend " > < / a>`end` | [`Date!`]( # date) | End of the range. |
| < a id = " timeframestart " > < / a>`start` | [`Date!`]( # date) | Start of the range. |
2021-06-08 01:23:25 +05:30
DOC
end
it_behaves_like 'renders correctly as GraphQL documentation'
end
2021-04-17 20:07:23 +05:30
context 'when there is an interface and a union' do
let ( :type ) do
user = Class . new ( :: Types :: BaseObject )
user . graphql_name 'User'
2021-10-27 15:23:28 +05:30
user . field :user_field , :: GraphQL :: Types :: String , null : true
2021-04-17 20:07:23 +05:30
group = Class . new ( :: Types :: BaseObject )
group . graphql_name 'Group'
2021-10-27 15:23:28 +05:30
group . field :group_field , :: GraphQL :: Types :: String , null : true
2021-04-17 20:07:23 +05:30
union = Class . new ( :: Types :: BaseUnion )
union . graphql_name 'UserOrGroup'
union . description 'Either a user or a group.'
union . possible_types user , group
interface = Module . new
interface . include ( :: Types :: BaseInterface )
interface . graphql_name 'Flying'
interface . description 'Something that can fly.'
2021-10-27 15:23:28 +05:30
interface . field :flight_speed , GraphQL :: Types :: Int , null : true , description : 'Speed in mph.'
2021-04-17 20:07:23 +05:30
african_swallow = Class . new ( :: Types :: BaseObject )
african_swallow . graphql_name 'AfricanSwallow'
african_swallow . description 'A swallow from Africa.'
african_swallow . implements interface
interface . orphan_types african_swallow
Class . new ( :: Types :: BaseObject ) do
2021-06-08 01:23:25 +05:30
graphql_name 'AbstractTypeTest'
2021-04-17 20:07:23 +05:30
description 'A test for abstract types.'
field :foo , union , null : true , description : 'The foo.'
field :flying , interface , null : true , description : 'A flying thing.'
end
end
it 'lists the fields correctly, and includes descriptions of all the types' do
type_section = << ~ DOC
2021-06-08 01:23:25 +05:30
### `AbstractTypeTest`
2021-04-17 20:07:23 +05:30
A test for abstract types .
2021-06-08 01:23:25 +05:30
#### Fields
| Name | Type | Description |
| - - - - | - - - - | - - - - - - - - - - - |
| < a id = " abstracttypetestflying " > < / a>`flying` | [`Flying`]( # flying) | A flying thing. |
| < a id = " abstracttypetestfoo " > < / a>`foo` | [`UserOrGroup`]( # userorgroup) | The foo. |
2021-04-17 20:07:23 +05:30
DOC
union_section = << ~ DOC
#### `UserOrGroup`
Either a user or a group .
One of :
- [ ` Group ` ] ( #group)
- [ ` User ` ] ( #user)
DOC
interface_section = << ~ DOC
#### `Flying`
Something that can fly .
Implementations :
- [ ` AfricanSwallow ` ] ( #africanswallow)
2021-06-08 01:23:25 +05:30
##### Fields
| Name | Type | Description |
| - - - - | - - - - | - - - - - - - - - - - |
| < a id = " flyingflightspeed " > < / a>`flightSpeed` | [`Int`]( # int) | Speed in mph. |
2021-04-17 20:07:23 +05:30
DOC
implementation_section = << ~ DOC
### `AfricanSwallow`
A swallow from Africa .
2021-06-08 01:23:25 +05:30
#### Fields
| Name | Type | Description |
| - - - - | - - - - | - - - - - - - - - - - |
| < a id = " africanswallowflightspeed " > < / a>`flightSpeed` | [`Int`]( # int) | Speed in mph. |
2021-04-17 20:07:23 +05:30
DOC
is_expected . to include (
type_section ,
union_section ,
interface_section ,
implementation_section
)
end
end
2020-04-08 14:13:33 +05:30
end
end