Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
652d8b33ee
commit
d6085b68c5
18 changed files with 1058 additions and 408 deletions
|
@ -1 +1 @@
|
|||
b6dda5d1f7a7e05c34ed0f72f161a46aee536d75
|
||||
6715e04b0a20714776227eaa67d68a6fa1ccfbdf
|
||||
|
|
|
@ -73,7 +73,7 @@ These features can also help with compliance requirements:
|
|||
- [**Generate reports on permission levels of users**](../user/admin_area/index.md#user-permission-export) (for
|
||||
instances): Administrators can generate a report listing all users' access permissions for groups and projects in the
|
||||
instance.
|
||||
- [**Lock project membership to group**](../user/group/index.md#prevent-members-from-being-added-to-a-group) (for
|
||||
- [**Lock project membership to group**](../user/group/index.md#prevent-members-from-being-added-to-projects-in-a-group) (for
|
||||
groups): Group owners can prevent new members from being added to projects within a group.
|
||||
- [**LDAP group sync**](auth/ldap/ldap_synchronization.md#group-sync) (for instances): Gives administrators the ability
|
||||
to automatically sync groups and manage SSH keys, permissions, and authentication, so you can focus on building your
|
||||
|
|
|
@ -788,7 +788,7 @@ Parameters:
|
|||
| `name` | string | yes | The name of the group. |
|
||||
| `path` | string | yes | The path of the group. |
|
||||
| `description` | string | no | The group's description. |
|
||||
| `membership_lock` | boolean | no | **(PREMIUM)** Prevent adding new members to project membership within this group. |
|
||||
| `membership_lock` | boolean | no | **(PREMIUM)** Prevent adding new members to projects within this group. |
|
||||
| `visibility` | string | no | The group's visibility. Can be `private`, `internal`, or `public`. |
|
||||
| `share_with_group_lock` | boolean | no | Prevent sharing a project with another group within this group. |
|
||||
| `require_two_factor_authentication` | boolean | no | Require all users in this group to setup Two-factor authentication. |
|
||||
|
@ -864,7 +864,7 @@ PUT /groups/:id
|
|||
| `name` | string | no | The name of the group. |
|
||||
| `path` | string | no | The path of the group. |
|
||||
| `description` | string | no | The description of the group. |
|
||||
| `membership_lock` | boolean | no | **(PREMIUM)** Prevent adding new members to project membership within this group. |
|
||||
| `membership_lock` | boolean | no | **(PREMIUM)** Prevent adding new members to projects within this group. |
|
||||
| `share_with_group_lock` | boolean | no | Prevent sharing a project with another group within this group. |
|
||||
| `visibility` | string | no | The visibility level of the group. Can be `private`, `internal`, or `public`. |
|
||||
| `require_two_factor_authentication` | boolean | no | Require all users in this group to setup Two-factor authentication. |
|
||||
|
|
|
@ -381,7 +381,7 @@ first time.
|
|||
### Requesting a review
|
||||
|
||||
When you are ready to have your merge request reviewed,
|
||||
you should request an initial review by assigning it to a reviewer from your group or team.
|
||||
you should [request an initial review](../user/project/merge_requests/getting_started.md#reviewer) by selecting a reviewer from your group or team.
|
||||
However, you can also assign it to any reviewer. The list of reviewers can be found on [Engineering projects](https://about.gitlab.com/handbook/engineering/projects/) page.
|
||||
|
||||
You can also use `workflow::ready for review` label. That means that your merge request is ready to be reviewed and any reviewer can pick it. It is recommended to use that label only if there isn't time pressure and make sure the merge request is assigned to a reviewer.
|
||||
|
|
|
@ -28,7 +28,7 @@ the tiers are no longer mentioned in GitLab documentation:
|
|||
- [Creating group memberships via CN](../user/group/index.md#create-group-links-via-cn)
|
||||
- [Group push rules](../user/group/index.md#group-push-rules)
|
||||
- [Managing group memberships via LDAP](../user/group/index.md#manage-group-memberships-via-ldap)
|
||||
- [Member locking](../user/group/index.md#prevent-members-from-being-added-to-a-group)
|
||||
- [Member locking](../user/group/index.md#prevent-members-from-being-added-to-projects-in-a-group)
|
||||
- [Overriding user permissions](../user/group/index.md#override-user-permissions)
|
||||
- [User contribution analytics](../user/group/contribution_analytics/index.md)
|
||||
- [Kerberos integration](../integration/kerberos.md)
|
||||
|
|
|
@ -508,7 +508,7 @@ To prevent a project from being shared with other groups:
|
|||
This setting applies to all subgroups unless overridden by a group owner. Groups already
|
||||
added to a project lose access when the setting is enabled.
|
||||
|
||||
## Prevent members from being added to a group **(PREMIUM)**
|
||||
## Prevent members from being added to projects in a group **(PREMIUM)**
|
||||
|
||||
As a group owner, you can prevent any new project membership for all
|
||||
projects in a group, allowing tighter control over project membership.
|
||||
|
@ -516,7 +516,11 @@ projects in a group, allowing tighter control over project membership.
|
|||
For example, if you want to lock the group for an [Audit Event](../../administration/audit_events.md),
|
||||
you can guarantee that project membership cannot be modified during the audit.
|
||||
|
||||
To prevent members from being added to a group:
|
||||
You can still invite groups or to add members to groups, implicitly giving members access to projects in the **locked** group.
|
||||
|
||||
The setting does not cascade. Projects in subgroups observe the subgroup configuration, ignoring the parent group.
|
||||
|
||||
To prevent members from being added to projects in a group:
|
||||
|
||||
1. Go to the group's **Settings > General** page.
|
||||
1. Expand the **Permissions, LFS, 2FA** section.
|
||||
|
|
|
@ -26247,7 +26247,7 @@ msgstr ""
|
|||
msgid "Prev"
|
||||
msgstr ""
|
||||
|
||||
msgid "Prevent adding new members to project membership within this group"
|
||||
msgid "Prevent adding new members to projects within this group"
|
||||
msgstr ""
|
||||
|
||||
msgid "Prevent auto-stopping"
|
||||
|
|
|
@ -8,11 +8,15 @@ module RuboCop
|
|||
TRANSLATION_METHODS = %i[_ s_ n_].freeze
|
||||
|
||||
def_node_matcher :translation_method?, <<~PATTERN
|
||||
(send _ _ str*)
|
||||
(send _ _ str*)
|
||||
PATTERN
|
||||
|
||||
def_node_matcher :lambda_node?, <<~PATTERN
|
||||
(send _ :lambda)
|
||||
(send _ :lambda)
|
||||
PATTERN
|
||||
|
||||
def_node_matcher :struct_constant_assignment?, <<~PATTERN
|
||||
(casgn _ _ `(const _ :Struct))
|
||||
PATTERN
|
||||
|
||||
def on_send(node)
|
||||
|
@ -27,7 +31,7 @@ module RuboCop
|
|||
receiver, _ = *ancestor
|
||||
break if lambda_node?(receiver) # translations defined in lambda nodes should be allowed
|
||||
|
||||
if constant_assignment?(ancestor)
|
||||
if constant_assignment?(ancestor) && !struct_constant_assignment?(ancestor)
|
||||
add_offense(node, location: :expression)
|
||||
|
||||
break
|
||||
|
|
792
spec/fixtures/markdown/markdown_golden_master_examples.yml
vendored
Normal file
792
spec/fixtures/markdown/markdown_golden_master_examples.yml
vendored
Normal file
|
@ -0,0 +1,792 @@
|
|||
# Related Specs:
|
||||
#
|
||||
# This data file drives the specs in the following specs:
|
||||
#
|
||||
# CE Backend: spec/requests/api/markdown_golden_master_spec.rb
|
||||
# CE Frontend: spec/frontend/content_editor/markdown_processing_spec.js
|
||||
#
|
||||
# For EE, these files are used:
|
||||
# EE Data: ee/spec/fixtures/markdown/markdown_golden_master_examples.yml
|
||||
# EE Backend: ee/spec/requests/api/markdown_golden_master_spec.rb
|
||||
# EE Frontend: ee/spec/frontend/content_editor/markdown_processing_spec.js
|
||||
#
|
||||
#
|
||||
# Requirements:
|
||||
#
|
||||
# 1. Frontend: We should have test coverage that the Content Editor can properly serialize HTML
|
||||
# to Markdown for all GFM source elements which it currently supports.
|
||||
# 2. Frontend: We should have test coverage that the Content Editor can properly render the expected
|
||||
# HTML for all GFM source elements which it currently supports (not currently implemented in the
|
||||
# frontend - this will likely be a standalone module outside of the Content Editor).
|
||||
# 3. Backend: We should ensure that for all GFM elements, the backend always renders the expected
|
||||
# HTML, for **all** supported GFM source elements.
|
||||
#
|
||||
# If any of this this ever changes unexpectedly, tests will start failing, and force the same change
|
||||
# to be made on the backend and frontend.
|
||||
#
|
||||
#
|
||||
# Overview:
|
||||
#
|
||||
# These specs ensure that the bidirectional Markdown <-> HTML conversion logic is implemented
|
||||
# identically on the backend and frontend, for all supported GitLab-Flavored Markdown examples, by
|
||||
# running hardcoded examples through the logic and ensuring the results match.
|
||||
#
|
||||
# This is an example of the "Golden Master Testing" approach, which is also referred to as
|
||||
# "Approval Testing" or "Characterization Testing".
|
||||
#
|
||||
# The term "Golden Master" originally comes from the recording industry, and refers to process
|
||||
# of "mastering", or making a final mix from which all other copies will be produced.
|
||||
#
|
||||
# See:
|
||||
# - https://en.wikipedia.org/wiki/Characterization_test
|
||||
# - https://en.wikipedia.org/wiki/Gold_master_(disambiguation)
|
||||
#
|
||||
#
|
||||
# What we are doing is actually a type Golden Master testing with modifications:
|
||||
#
|
||||
# 1. The original markdown examples used to drive the tests are taken from this YAML, and can be
|
||||
# considered a form of "fixture" in this case.
|
||||
# 2. The HTML in the YAML is the "Golden Master", but we are going to use it to assert
|
||||
# against **TWO** different implementations of markdown rendering:
|
||||
# 1. The frontend, implemented as Jest specs.
|
||||
# 1. This will assert both HTML -> markdown serialization (what it currently does), as well as...
|
||||
# 2. Markdown -> HTML rendering (not currently implemented in the frontend - this will likely
|
||||
# be a standalone module outside of the Content Editor)
|
||||
# 1. The backend, implemented as requests specs
|
||||
# 1. This will assert markdown -> HTML conversion by the backend.
|
||||
#
|
||||
# Also see the MR for more explanation on the details of this approach:
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68671
|
||||
#
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# * Please keep this file alphabetized.
|
||||
# * To run focused example(s), set the `FOCUSED_MARKDOWN_EXAMPLES` environment variable to a
|
||||
# comma-separated list of example names. This works for the frontend and backend specs.
|
||||
# * Required attributes for every example:
|
||||
# 1. `name`: Specifies the Name of the example, which will be printed when specs are run.
|
||||
# 2. `markdown`: Specifies the Markdown for the example, which will be compared with the
|
||||
# Markdown the code generates from the corresponding specified HTML.
|
||||
# 3. `html`: Specifies the HTML for the example, which will be compared with the
|
||||
# HTML the code generated from the corresponding specified Markdown.
|
||||
# * `api_context` (optional): This is used when a single markdown can be
|
||||
# rendered differently depending on the API endpoint or area of the app from which it is called or
|
||||
# used. The valid values for `api_context` are: `project`, `group`, `project_wiki`,
|
||||
# and (for EE only) `group_wiki`.The `name` attribute must also have a `_for_[API_CONTEXT]` suffix
|
||||
# which matches the `api_context`, in order to ensure that each example has a unique `name`
|
||||
# identifier. For example, `attachment_image_for_project`.
|
||||
# * `pending`: To skip an example that is broken or not yet fully implemented, add
|
||||
# a `pending: <reason with issue/MR URL>` attribute to the example. See
|
||||
# the `a_example_of_pending` entry for an example.
|
||||
# * `pending` with key: You can also mark an example pending on only the frontend or backend. See
|
||||
# the `a_example_of_pending_with_keys` entry for an example.
|
||||
# * `substitutions`: For examples which may have variable content in different environments,
|
||||
# such as portions of the URI, or database record IDs, you can specify
|
||||
# `substitutions`, which is an array of regex/replacement pairs. The HTML
|
||||
# value will be normalized with each of these pairs using Ruby `gsub`
|
||||
# before comparing.
|
||||
# The substitution values can (and are) also reused in multiple examples
|
||||
# via YAML anchors.
|
||||
#
|
||||
#
|
||||
# Notes:
|
||||
#
|
||||
# * The html values should exactly match what the backend markdown API endpoints return for the
|
||||
# given markdown example. The HTML is intentionally not indented, formatted, or split across lines.
|
||||
# This is a bit less readable, but it makes the spec logic simpler and less error prone for edge
|
||||
# cases.
|
||||
#
|
||||
#
|
||||
# Debugging Failures and Writing New Entries:
|
||||
#
|
||||
# * You need to compare what is different between the expected and actual values.
|
||||
# * In rspec, the diff printed out includes the full text of the HTML. This may be long, so you
|
||||
# may want to turn line wrapping on or off or copy the diff to separate file(s) for easier comparison.
|
||||
# * If the difference is just in an attribute value, use the `substitutions` support to normalize
|
||||
# the HTML before comparing. These specs are only validating the HTML structure, the individual
|
||||
# markdown elements' unit tests can provide coverage that the exact attribute values are correct.
|
||||
# * If you are making a new entry, you can create the entry according to the `Usage` section above,
|
||||
# but leave the `html` value blank. This will cause the spec to fail, and you can fill in the
|
||||
# `html` value based on the spec failure that is printed out.
|
||||
|
||||
---
|
||||
|
||||
#- name: an_example_of_pending
|
||||
# pending: 'This is an example of the pending attribute: http://example.com'
|
||||
# markdown: ;)
|
||||
# html: |-
|
||||
# <blink data-sourcepos="1:1-1:2"/></blink>
|
||||
#
|
||||
|
||||
#- name: an_example_of_pending_with_keys
|
||||
# pending:
|
||||
# frontend: 'This is an example of the frontend-only pending attribute: http://example.com'
|
||||
# backend: 'This is an example of the backend-only pending attribute: http://example.com'
|
||||
# markdown: ;)
|
||||
# html: |-
|
||||
# <blink data-sourcepos="1:1-1:2"/></blink>
|
||||
|
||||
- name: attachment_image_for_group
|
||||
api_context: group
|
||||
substitutions:
|
||||
# Note: having the top level `substitutions` data structure be a hash of arrays
|
||||
# allows us to compose multiple substitutions via YAML anchors (YAML anchors
|
||||
# pointing to arrays can't be combined)
|
||||
uri_substitution: &uri_substitution
|
||||
# NOTE: We don't care about verifying specific attribute values here, that should be the
|
||||
# responsibility of unit tests. These tests are about the structure of the HTML.
|
||||
- regex: '(href|data-src)(=")(.*?)(test-file\.(png|zip)")'
|
||||
replacement: '\1\2URI_PREFIX\4'
|
||||
markdown: |-
|
||||
![test-file](/uploads/aa45a38ec2cfe97433281b10bbff042c/test-file.png)
|
||||
html: |-
|
||||
<p data-sourcepos="1:1-1:69" dir="auto"><a class="no-attachment-icon gfm" href="/groups/group58/-/uploads/aa45a38ec2cfe97433281b10bbff042c/test-file.png" target="_blank" rel="noopener noreferrer" data-canonical-src="/uploads/aa45a38ec2cfe97433281b10bbff042c/test-file.png" data-link="true"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="test-file" class="lazy gfm" data-src="/groups/group58/-/uploads/aa45a38ec2cfe97433281b10bbff042c/test-file.png" data-canonical-src="/uploads/aa45a38ec2cfe97433281b10bbff042c/test-file.png"></a></p>
|
||||
|
||||
- name: attachment_image_for_project
|
||||
api_context: project
|
||||
substitutions:
|
||||
uri_substitution: *uri_substitution
|
||||
markdown: |-
|
||||
![test-file](/uploads/aa45a38ec2cfe97433281b10bbff042c/test-file.png)
|
||||
html: |-
|
||||
<p data-sourcepos="1:1-1:69" dir="auto"><a class="no-attachment-icon gfm" href="/group58/project22/uploads/aa45a38ec2cfe97433281b10bbff042c/test-file.png" target="_blank" rel="noopener noreferrer" data-canonical-src="/uploads/aa45a38ec2cfe97433281b10bbff042c/test-file.png" data-link="true"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="test-file" class="lazy gfm" data-src="/group58/project22/uploads/aa45a38ec2cfe97433281b10bbff042c/test-file.png" data-canonical-src="/uploads/aa45a38ec2cfe97433281b10bbff042c/test-file.png"></a></p>
|
||||
|
||||
- name: attachment_image_for_project_wiki
|
||||
api_context: project_wiki
|
||||
substitutions:
|
||||
uri_substitution: *uri_substitution
|
||||
markdown: |-
|
||||
![test-file](test-file.png)
|
||||
html: |-
|
||||
<p data-sourcepos="1:1-1:27" dir="auto"><a class="no-attachment-icon" href="/group1/project1/-/wikis/test-file.png" target="_blank" rel="noopener noreferrer" data-canonical-src="test-file.png"><img alt="test-file" class="lazy" data-src="/group1/project1/-/wikis/test-file.png" data-canonical-src="test-file.png"></a></p>
|
||||
|
||||
- name: attachment_link_for_group
|
||||
api_context: group
|
||||
substitutions:
|
||||
uri_substitution: *uri_substitution
|
||||
markdown: |-
|
||||
[test-file](/uploads/aa45a38ec2cfe97433281b10bbff042c/test-file.zip)
|
||||
html: |-
|
||||
<p data-sourcepos="1:1-1:68" dir="auto"><a href="/groups/group58/-/uploads/aa45a38ec2cfe97433281b10bbff042c/test-file.zip" data-canonical-src="/uploads/aa45a38ec2cfe97433281b10bbff042c/test-file.zip" data-link="true" class="gfm">test-file</a></p>
|
||||
|
||||
- name: attachment_link_for_project
|
||||
api_context: project
|
||||
substitutions:
|
||||
uri_substitution: *uri_substitution
|
||||
markdown: |-
|
||||
[test-file](/uploads/aa45a38ec2cfe97433281b10bbff042c/test-file.zip)
|
||||
html: |-
|
||||
<p data-sourcepos="1:1-1:68" dir="auto"><a href="/group58/project22/uploads/aa45a38ec2cfe97433281b10bbff042c/test-file.zip" data-canonical-src="/uploads/aa45a38ec2cfe97433281b10bbff042c/test-file.zip" data-link="true" class="gfm">test-file</a></p>
|
||||
|
||||
- name: attachment_link_for_project_wiki
|
||||
api_context: project_wiki
|
||||
substitutions:
|
||||
uri_substitution: *uri_substitution
|
||||
# TODO: The current frontend example doesn't include the path, need to look into why it does after refactoring to the new golden master approach
|
||||
pending:
|
||||
frontend: 'The current frontend example doesnt include the path, need to look into why it does after refactoring to the new golden master approach'
|
||||
markdown: |-
|
||||
[test-file](test-file.zip)
|
||||
html: |-
|
||||
<p data-sourcepos="1:1-1:26" dir="auto"><a href="/group1/project1/-/wikis/test-file.zip" data-canonical-src="test-file.zip">test-file</a></p>
|
||||
|
||||
- name: audio
|
||||
markdown: |-
|
||||
![Sample Audio](https://gitlab.com/gitlab.mp3)
|
||||
html: |-
|
||||
<p data-sourcepos="1:1-1:46" dir="auto"><span class="media-container audio-container"><audio src="https://gitlab.com/gitlab.mp3" controls="true" data-setup="{}" data-title="Sample Audio"></audio><a href="https://gitlab.com/gitlab.mp3" target="_blank" rel="nofollow noreferrer noopener" title="Download 'Sample Audio'">Sample Audio</a></span></p>
|
||||
|
||||
- name: audio_and_video_in_lists
|
||||
markdown: |-
|
||||
* ![Sample Audio](https://gitlab.com/1.mp3)
|
||||
* ![Sample Video](https://gitlab.com/2.mp4)
|
||||
|
||||
1. ![Sample Video](https://gitlab.com/1.mp4)
|
||||
2. ![Sample Audio](https://gitlab.com/2.mp3)
|
||||
|
||||
* [x] ![Sample Audio](https://gitlab.com/1.mp3)
|
||||
* [x] ![Sample Audio](https://gitlab.com/2.mp3)
|
||||
* [x] ![Sample Video](https://gitlab.com/3.mp4)
|
||||
html: |-
|
||||
<ul data-sourcepos="1:1-3:0" dir="auto">
|
||||
<li data-sourcepos="1:1-1:43"><span class="media-container audio-container"><audio src="https://gitlab.com/1.mp3" controls="true" data-setup="{}" data-title="Sample Audio"></audio><a href="https://gitlab.com/1.mp3" target="_blank" rel="nofollow noreferrer noopener" title="Download 'Sample Audio'">Sample Audio</a></span></li>
|
||||
<li data-sourcepos="2:1-3:0"><span class="media-container video-container"><video src="https://gitlab.com/2.mp4" controls="true" data-setup="{}" data-title="Sample Video" width="400" preload="metadata"></video><a href="https://gitlab.com/2.mp4" target="_blank" rel="nofollow noreferrer noopener" title="Download 'Sample Video'">Sample Video</a></span></li>
|
||||
</ul>
|
||||
<ol data-sourcepos="4:1-6:0" dir="auto">
|
||||
<li data-sourcepos="4:1-4:44"><span class="media-container video-container"><video src="https://gitlab.com/1.mp4" controls="true" data-setup="{}" data-title="Sample Video" width="400" preload="metadata"></video><a href="https://gitlab.com/1.mp4" target="_blank" rel="nofollow noreferrer noopener" title="Download 'Sample Video'">Sample Video</a></span></li>
|
||||
<li data-sourcepos="5:1-6:0"><span class="media-container audio-container"><audio src="https://gitlab.com/2.mp3" controls="true" data-setup="{}" data-title="Sample Audio"></audio><a href="https://gitlab.com/2.mp3" target="_blank" rel="nofollow noreferrer noopener" title="Download 'Sample Audio'">Sample Audio</a></span></li>
|
||||
</ol>
|
||||
<ul data-sourcepos="7:1-9:47" class="task-list" dir="auto">
|
||||
<li data-sourcepos="7:1-7:47" class="task-list-item">
|
||||
<input type="checkbox" class="task-list-item-checkbox" checked disabled> <span class="media-container audio-container"><audio src="https://gitlab.com/1.mp3" controls="true" data-setup="{}" data-title="Sample Audio"></audio><a href="https://gitlab.com/1.mp3" target="_blank" rel="nofollow noreferrer noopener" title="Download 'Sample Audio'">Sample Audio</a></span>
|
||||
</li>
|
||||
<li data-sourcepos="8:1-8:47" class="task-list-item">
|
||||
<input type="checkbox" class="task-list-item-checkbox" checked disabled> <span class="media-container audio-container"><audio src="https://gitlab.com/2.mp3" controls="true" data-setup="{}" data-title="Sample Audio"></audio><a href="https://gitlab.com/2.mp3" target="_blank" rel="nofollow noreferrer noopener" title="Download 'Sample Audio'">Sample Audio</a></span>
|
||||
</li>
|
||||
<li data-sourcepos="9:1-9:47" class="task-list-item">
|
||||
<input type="checkbox" class="task-list-item-checkbox" checked disabled> <span class="media-container video-container"><video src="https://gitlab.com/3.mp4" controls="true" data-setup="{}" data-title="Sample Video" width="400" preload="metadata"></video><a href="https://gitlab.com/3.mp4" target="_blank" rel="nofollow noreferrer noopener" title="Download 'Sample Video'">Sample Video</a></span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
- name: blockquote
|
||||
markdown: |-
|
||||
> This is a blockquote
|
||||
>
|
||||
> This is another one
|
||||
html: |-
|
||||
<blockquote data-sourcepos="1:1-3:21" dir="auto">
|
||||
<p data-sourcepos="1:3-1:22">This is a blockquote</p>
|
||||
<p data-sourcepos="3:3-3:21">This is another one</p>
|
||||
</blockquote>
|
||||
|
||||
- name: bold
|
||||
markdown: |-
|
||||
**bold**
|
||||
html: |-
|
||||
<p data-sourcepos="1:1-1:8" dir="auto"><strong>bold</strong></p>
|
||||
|
||||
- name: bullet_list_style_1
|
||||
markdown: |-
|
||||
* list item 1
|
||||
* list item 2
|
||||
* embedded list item 3
|
||||
html: |-
|
||||
<ul data-sourcepos="1:1-3:24" dir="auto">
|
||||
<li data-sourcepos="1:1-1:13">list item 1</li>
|
||||
<li data-sourcepos="2:1-3:24">list item 2
|
||||
<ul data-sourcepos="3:3-3:24">
|
||||
<li data-sourcepos="3:3-3:24">embedded list item 3</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
- name: bullet_list_style_2
|
||||
markdown: |-
|
||||
- list item 1
|
||||
- list item 2
|
||||
* embedded list item 3
|
||||
html: |-
|
||||
<ul data-sourcepos="1:1-3:24" dir="auto">
|
||||
<li data-sourcepos="1:1-1:13">list item 1</li>
|
||||
<li data-sourcepos="2:1-3:24">list item 2
|
||||
<ul data-sourcepos="3:3-3:24">
|
||||
<li data-sourcepos="3:3-3:24">embedded list item 3</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
- name: bullet_list_style_3
|
||||
markdown: |-
|
||||
+ list item 1
|
||||
+ list item 2
|
||||
- embedded list item 3
|
||||
html: |-
|
||||
<ul data-sourcepos="1:1-3:24" dir="auto">
|
||||
<li data-sourcepos="1:1-1:13">list item 1</li>
|
||||
<li data-sourcepos="2:1-3:24">list item 2
|
||||
<ul data-sourcepos="3:3-3:24">
|
||||
<li data-sourcepos="3:3-3:24">embedded list item 3</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
- name: code_block
|
||||
markdown: |-
|
||||
```javascript
|
||||
console.log('hello world')
|
||||
```
|
||||
html: |-
|
||||
<pre data-sourcepos="1:1-3:3" class="code highlight js-syntax-highlight language-javascript" lang="javascript" v-pre="true"><code><span id="LC1" class="line" lang="javascript"> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">hello world</span><span class="dl">'</span><span class="p">)</span></span></code></pre>
|
||||
|
||||
- name: color_chips
|
||||
markdown: |-
|
||||
- `#F00`
|
||||
- `#F00A`
|
||||
- `#FF0000`
|
||||
- `#FF0000AA`
|
||||
- `RGB(0,255,0)`
|
||||
- `RGB(0%,100%,0%)`
|
||||
- `RGBA(0,255,0,0.3)`
|
||||
- `HSL(540,70%,50%)`
|
||||
- `HSLA(540,70%,50%,0.3)`
|
||||
html: |-
|
||||
<ul data-sourcepos="1:1-9:25" dir="auto">
|
||||
<li data-sourcepos="1:1-1:8"><code>#F00<span class="gfm-color_chip"><span style="background-color: #F00;"></span></span></code></li>
|
||||
<li data-sourcepos="2:1-2:9"><code>#F00A<span class="gfm-color_chip"><span style="background-color: #F00A;"></span></span></code></li>
|
||||
<li data-sourcepos="3:1-3:11"><code>#FF0000<span class="gfm-color_chip"><span style="background-color: #FF0000;"></span></span></code></li>
|
||||
<li data-sourcepos="4:1-4:13"><code>#FF0000AA<span class="gfm-color_chip"><span style="background-color: #FF0000AA;"></span></span></code></li>
|
||||
<li data-sourcepos="5:1-5:16"><code>RGB(0,255,0)<span class="gfm-color_chip"><span style="background-color: RGB(0,255,0);"></span></span></code></li>
|
||||
<li data-sourcepos="6:1-6:19"><code>RGB(0%,100%,0%)<span class="gfm-color_chip"><span style="background-color: RGB(0%,100%,0%);"></span></span></code></li>
|
||||
<li data-sourcepos="7:1-7:21"><code>RGBA(0,255,0,0.3)<span class="gfm-color_chip"><span style="background-color: RGBA(0,255,0,0.3);"></span></span></code></li>
|
||||
<li data-sourcepos="8:1-8:20"><code>HSL(540,70%,50%)<span class="gfm-color_chip"><span style="background-color: HSL(540,70%,50%);"></span></span></code></li>
|
||||
<li data-sourcepos="9:1-9:25"><code>HSLA(540,70%,50%,0.3)<span class="gfm-color_chip"><span style="background-color: HSLA(540,70%,50%,0.3);"></span></span></code></li>
|
||||
</ul>
|
||||
|
||||
- name: description_list
|
||||
markdown: |-
|
||||
<dl>
|
||||
<dt>Frog</dt>
|
||||
<dd>Wet green thing</dd>
|
||||
<dt>Rabbit</dt>
|
||||
<dd>Warm fluffy thing</dd>
|
||||
<dt>Punt</dt>
|
||||
<dd>Kick a ball</dd>
|
||||
<dd>Take a bet</dd>
|
||||
<dt>Color</dt>
|
||||
<dt>Colour</dt>
|
||||
<dd>
|
||||
|
||||
Any hue except _white_ or **black**
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
html: |-
|
||||
<dl>
|
||||
<dt>Frog</dt>
|
||||
<dd>Wet green thing</dd>
|
||||
<dt>Rabbit</dt>
|
||||
<dd>Warm fluffy thing</dd>
|
||||
<dt>Punt</dt>
|
||||
<dd>Kick a ball</dd>
|
||||
<dd>Take a bet</dd>
|
||||
<dt>Color</dt>
|
||||
<dt>Colour</dt>
|
||||
<dd>
|
||||
<p data-sourcepos="13:1-13:35">Any hue except <em>white</em> or <strong>black</strong></p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
- name: details
|
||||
markdown: |-
|
||||
<details>
|
||||
<summary>This is the visible summary of the collapsible section</summary>
|
||||
|
||||
1. collapsed markdown
|
||||
2. more collapsed markdown
|
||||
|
||||
</details>
|
||||
html: |-
|
||||
<details>
|
||||
<summary>This is the visible summary of the collapsible section</summary>
|
||||
<ol data-sourcepos="4:1-6:0">
|
||||
<li data-sourcepos="4:1-4:21">collapsed markdown</li>
|
||||
<li data-sourcepos="5:1-6:0">more collapsed markdown</li>
|
||||
</ol>
|
||||
</details>
|
||||
|
||||
- name: div
|
||||
markdown: |-
|
||||
<div>plain text</div>
|
||||
<div>
|
||||
|
||||
just a plain ol' div, not much to _expect_!
|
||||
|
||||
</div>
|
||||
html: |-
|
||||
<div>plain text</div>
|
||||
<div>
|
||||
<p data-sourcepos="4:1-4:43">just a plain ol' div, not much to <em>expect</em>!</p>
|
||||
</div>
|
||||
|
||||
- name: emoji
|
||||
markdown: |-
|
||||
:sparkles: :heart: :100:
|
||||
html: |-
|
||||
<p data-sourcepos="1:1-1:24" dir="auto"><gl-emoji title="sparkles" data-name="sparkles" data-unicode-version="6.0">✨</gl-emoji> <gl-emoji title="heavy black heart" data-name="heart" data-unicode-version="1.1">❤</gl-emoji> <gl-emoji title="hundred points symbol" data-name="100" data-unicode-version="6.0">💯</gl-emoji></p>
|
||||
|
||||
- name: emphasis
|
||||
markdown: _emphasized text_
|
||||
html: <p data-sourcepos="1:1-1:17" dir="auto"><em>emphasized text</em></p>
|
||||
|
||||
- name: figure
|
||||
markdown: |-
|
||||
<figure>
|
||||
|
||||
![Elephant at sunset](elephant-sunset.jpg)
|
||||
|
||||
<figcaption>An elephant at sunset</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
|
||||
![A crocodile wearing crocs](croc-crocs.jpg)
|
||||
|
||||
<figcaption>
|
||||
|
||||
A crocodile wearing _crocs_!
|
||||
|
||||
</figcaption>
|
||||
</figure>
|
||||
html: |-
|
||||
<figure>
|
||||
<p data-sourcepos="3:1-3:42"><a class="no-attachment-icon" href="elephant-sunset.jpg" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="Elephant at sunset" class="lazy" data-src="elephant-sunset.jpg"></a></p>
|
||||
<figcaption>An elephant at sunset</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<p data-sourcepos="9:1-9:44"><a class="no-attachment-icon" href="croc-crocs.jpg" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="A crocodile wearing crocs" class="lazy" data-src="croc-crocs.jpg"></a></p>
|
||||
<figcaption>
|
||||
<p data-sourcepos="13:1-13:28">A crocodile wearing <em>crocs</em>!</p>
|
||||
</figcaption>
|
||||
</figure>
|
||||
|
||||
- name: frontmatter_json
|
||||
markdown: |-
|
||||
;;;
|
||||
{
|
||||
"title": "Page title"
|
||||
}
|
||||
;;;
|
||||
html: |-
|
||||
<pre data-sourcepos="1:1-5:3" class="code highlight js-syntax-highlight language-json" lang="json" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="json"><span class="p">{</span></span>
|
||||
<span id="LC2" class="line" lang="json"><span class="w"> </span><span class="nl">"title"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Page title"</span></span>
|
||||
<span id="LC3" class="line" lang="json"><span class="p">}</span></span></code></pre>
|
||||
|
||||
- name: frontmatter_toml
|
||||
markdown: |-
|
||||
+++
|
||||
title = "Page title"
|
||||
+++
|
||||
html: <pre data-sourcepos="1:1-3:3" class="code highlight js-syntax-highlight language-toml" lang="toml" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="toml"><span class="py">title</span> <span class="p">=</span> <span class="s">"Page title"</span></span></code></pre>
|
||||
|
||||
- name: frontmatter_yaml
|
||||
markdown: |-
|
||||
---
|
||||
title: Page title
|
||||
---
|
||||
html: <pre data-sourcepos="1:1-3:3" class="code highlight js-syntax-highlight language-yaml" lang="yaml" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="yaml"><span class="na">title</span><span class="pi">:</span> <span class="s">Page title</span></span></code></pre>
|
||||
|
||||
- name: hard_break
|
||||
markdown: |-
|
||||
This is a line after a\
|
||||
hard break
|
||||
html: |-
|
||||
<p data-sourcepos="1:1-2:10" dir="auto">This is a line after a<br>
|
||||
hard break</p>
|
||||
|
||||
- name: headings
|
||||
markdown: |-
|
||||
# Heading 1
|
||||
|
||||
## Heading 2
|
||||
|
||||
### Heading 3
|
||||
|
||||
#### Heading 4
|
||||
|
||||
##### Heading 5
|
||||
|
||||
###### Heading 6
|
||||
html: |-
|
||||
<h1 data-sourcepos="1:1-1:11" dir="auto">
|
||||
<a id="user-content-heading-1" class="anchor" href="#heading-1" aria-hidden="true"></a>Heading 1</h1>
|
||||
<h2 data-sourcepos="3:1-3:12" dir="auto">
|
||||
<a id="user-content-heading-2" class="anchor" href="#heading-2" aria-hidden="true"></a>Heading 2</h2>
|
||||
<h3 data-sourcepos="5:1-5:13" dir="auto">
|
||||
<a id="user-content-heading-3" class="anchor" href="#heading-3" aria-hidden="true"></a>Heading 3</h3>
|
||||
<h4 data-sourcepos="7:1-7:14" dir="auto">
|
||||
<a id="user-content-heading-4" class="anchor" href="#heading-4" aria-hidden="true"></a>Heading 4</h4>
|
||||
<h5 data-sourcepos="9:1-9:15" dir="auto">
|
||||
<a id="user-content-heading-5" class="anchor" href="#heading-5" aria-hidden="true"></a>Heading 5</h5>
|
||||
<h6 data-sourcepos="11:1-11:16" dir="auto">
|
||||
<a id="user-content-heading-6" class="anchor" href="#heading-6" aria-hidden="true"></a>Heading 6</h6>
|
||||
|
||||
- name: horizontal_rule
|
||||
markdown: |-
|
||||
---
|
||||
html: |-
|
||||
<hr data-sourcepos="1:1-1:3">
|
||||
|
||||
- name: html_marks
|
||||
markdown: |-
|
||||
* Content editor is ~~great~~<ins>amazing</ins>.
|
||||
* If the changes <abbr title="Looks good to merge">LGTM</abbr>, please <abbr title="Merge when pipeline succeeds">MWPS</abbr>.
|
||||
* The English song <q>Oh I do like to be beside the seaside</q> looks like this in Hebrew: <span dir="rtl">אה, אני אוהב להיות ליד חוף הים</span>. In the computer's memory, this is stored as <bdo dir="ltr">אה, אני אוהב להיות ליד חוף הים</bdo>.
|
||||
* <cite>The Scream</cite> by Edvard Munch. Painted in 1893.
|
||||
* <dfn>HTML</dfn> is the standard markup language for creating web pages.
|
||||
* Do not forget to buy <mark>milk</mark> today.
|
||||
* This is a paragraph and <small>smaller text goes here</small>.
|
||||
* The concert starts at <time datetime="20:00">20:00</time> and you'll be able to enjoy the band for at least <time datetime="PT2H30M">2h 30m</time>.
|
||||
* Press <kbd>Ctrl</kbd> + <kbd>C</kbd> to copy text (Windows).
|
||||
* WWF's goal is to: <q>Build a future where people live in harmony with nature.</q> We hope they succeed.
|
||||
* The error occured was: <samp>Keyboard not found. Press F1 to continue.</samp>
|
||||
* The area of a triangle is: 1/2 x <var>b</var> x <var>h</var>, where <var>b</var> is the base, and <var>h</var> is the vertical height.
|
||||
* <ruby>漢<rt>ㄏㄢˋ</rt></ruby>
|
||||
* C<sub>7</sub>H<sub>16</sub> + O<sub>2</sub> → CO<sub>2</sub> + H<sub>2</sub>O
|
||||
* The **Pythagorean theorem** is often expressed as <var>a<sup>2</sup></var> + <var>b<sup>2</sup></var> = <var>c<sup>2</sup></var>
|
||||
html: |-
|
||||
<ul data-sourcepos="1:1-15:130" dir="auto">
|
||||
<li data-sourcepos="1:1-1:48">Content editor is <del>great</del><ins>amazing</ins>.</li>
|
||||
<li data-sourcepos="2:1-2:126">If the changes <abbr title="Looks good to merge">LGTM</abbr>, please <abbr title="Merge when pipeline succeeds">MWPS</abbr>.</li>
|
||||
<li data-sourcepos="3:1-3:288">The English song <q>Oh I do like to be beside the seaside</q> looks like this in Hebrew: <span dir="rtl">אה, אני אוהב להיות ליד חוף הים</span>. In the computer's memory, this is stored as <bdo dir="ltr">אה, אני אוהב להיות ליד חוף הים</bdo>.</li>
|
||||
<li data-sourcepos="4:1-4:59">
|
||||
<cite>The Scream</cite> by Edvard Munch. Painted in 1893.</li>
|
||||
<li data-sourcepos="5:1-5:73">
|
||||
<dfn>HTML</dfn> is the standard markup language for creating web pages.</li>
|
||||
<li data-sourcepos="6:1-6:47">Do not forget to buy <mark>milk</mark> today.</li>
|
||||
<li data-sourcepos="7:1-7:64">This is a paragraph and <small>smaller text goes here</small>.</li>
|
||||
<li data-sourcepos="8:1-8:149">The concert starts at <time datetime="20:00">20:00</time> and you'll be able to enjoy the band for at least <time datetime="PT2H30M">2h 30m</time>.</li>
|
||||
<li data-sourcepos="9:1-9:62">Press <kbd>Ctrl</kbd> + <kbd>C</kbd> to copy text (Windows).</li>
|
||||
<li data-sourcepos="10:1-10:105">WWF's goal is to: <q>Build a future where people live in harmony with nature.</q> We hope they succeed.</li>
|
||||
<li data-sourcepos="11:1-11:79">The error occured was: <samp>Keyboard not found. Press F1 to continue.</samp>
|
||||
</li>
|
||||
<li data-sourcepos="12:1-12:136">The area of a triangle is: 1/2 x <var>b</var> x <var>h</var>, where <var>b</var> is the base, and <var>h</var> is the vertical height.</li>
|
||||
<li data-sourcepos="13:1-13:35"><ruby>漢<rt>ㄏㄢˋ</rt></ruby></li>
|
||||
<li data-sourcepos="14:1-14:81">C<sub>7</sub>H<sub>16</sub> + O<sub>2</sub> → CO<sub>2</sub> + H<sub>2</sub>O</li>
|
||||
<li data-sourcepos="15:1-15:130">The <strong>Pythagorean theorem</strong> is often expressed as <var>a<sup>2</sup></var> + <var>b<sup>2</sup></var> = <var>c<sup>2</sup></var>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
- name: image
|
||||
markdown: |-
|
||||
![alt text](https://gitlab.com/logo.png)
|
||||
html: |-
|
||||
<p data-sourcepos="1:1-1:40" dir="auto"><a class="no-attachment-icon" href="https://gitlab.com/logo.png" target="_blank" rel="nofollow noreferrer noopener"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="alt text" class="lazy" data-src="https://gitlab.com/logo.png"></a></p>
|
||||
|
||||
- name: inline_code
|
||||
markdown: |-
|
||||
`code`
|
||||
html: |-
|
||||
<p data-sourcepos="1:1-1:6" dir="auto"><code>code</code></p>
|
||||
|
||||
- name: inline_diff
|
||||
markdown: |-
|
||||
* {-deleted-}
|
||||
* {+added+}
|
||||
html: |-
|
||||
<ul data-sourcepos="1:1-2:11" dir="auto">
|
||||
<li data-sourcepos="1:1-1:13"><span class="idiff left right deletion">deleted</span></li>
|
||||
<li data-sourcepos="2:1-2:11"><span class="idiff left right addition">added</span></li>
|
||||
</ul>
|
||||
|
||||
- name: label
|
||||
pending:
|
||||
# TODO: There is an error with the frontend HTML to markdown spec adding a double escape (\\) to the label tilde.
|
||||
frontend: 'There is an error with the frontend HTML to markdown spec adding a double escape (\\) to the label tilde.'
|
||||
markdown: |-
|
||||
~bug
|
||||
html: |-
|
||||
<p data-sourcepos="1:1-1:4" dir="auto">~bug</p>
|
||||
|
||||
- name: link
|
||||
markdown: |-
|
||||
[GitLab](https://gitlab.com)
|
||||
html: |-
|
||||
<p data-sourcepos="1:1-1:28" dir="auto"><a href="https://gitlab.com" rel="nofollow noreferrer noopener" target="_blank">GitLab</a></p>
|
||||
|
||||
- name: math
|
||||
markdown: |-
|
||||
This math is inline $`a^2+b^2=c^2`$.
|
||||
|
||||
This is on a separate line:
|
||||
|
||||
```math
|
||||
a^2+b^2=c^2
|
||||
```
|
||||
html: |-
|
||||
<p data-sourcepos="1:1-1:36" dir="auto">This math is inline <code class="code math js-render-math" data-math-style="inline">a^2+b^2=c^2</code>.</p>
|
||||
<p data-sourcepos="3:1-3:27" dir="auto">This is on a separate line:</p>
|
||||
<pre data-sourcepos="5:1-7:3" class="code highlight js-syntax-highlight language-math js-render-math" lang="math" v-pre="true" data-math-style="display"><code><span id="LC1" class="line" lang="math">a^2+b^2=c^2</span></code></pre>
|
||||
|
||||
- name: ordered_list
|
||||
markdown: |-
|
||||
1. list item 1
|
||||
2. list item 2
|
||||
3. list item 3
|
||||
html: |-
|
||||
<ol data-sourcepos="1:1-3:14" dir="auto">
|
||||
<li data-sourcepos="1:1-1:14">list item 1</li>
|
||||
<li data-sourcepos="2:1-2:14">list item 2</li>
|
||||
<li data-sourcepos="3:1-3:14">list item 3</li>
|
||||
</ol>
|
||||
|
||||
- name: ordered_list_with_start_order
|
||||
markdown: |-
|
||||
134. list item 1
|
||||
135. list item 2
|
||||
136. list item 3
|
||||
html: |-
|
||||
<ol start="134" data-sourcepos="1:1-3:16" dir="auto">
|
||||
<li data-sourcepos="1:1-1:16">list item 1</li>
|
||||
<li data-sourcepos="2:1-2:16">list item 2</li>
|
||||
<li data-sourcepos="3:1-3:16">list item 3</li>
|
||||
</ol>
|
||||
|
||||
- name: ordered_task_list
|
||||
markdown: |-
|
||||
1. [x] hello
|
||||
2. [x] world
|
||||
3. [ ] example
|
||||
1. [ ] of nested
|
||||
1. [x] task list
|
||||
2. [ ] items
|
||||
html: |-
|
||||
<ol data-sourcepos="1:1-6:18" class="task-list" dir="auto">
|
||||
<li data-sourcepos="1:1-1:12" class="task-list-item">
|
||||
<input type="checkbox" class="task-list-item-checkbox" checked disabled> hello</li>
|
||||
<li data-sourcepos="2:1-2:12" class="task-list-item">
|
||||
<input type="checkbox" class="task-list-item-checkbox" checked disabled> world</li>
|
||||
<li data-sourcepos="3:1-6:18" class="task-list-item">
|
||||
<input type="checkbox" class="task-list-item-checkbox" disabled> example
|
||||
<ol data-sourcepos="4:4-6:18" class="task-list">
|
||||
<li data-sourcepos="4:4-6:18" class="task-list-item">
|
||||
<input type="checkbox" class="task-list-item-checkbox" disabled> of nested
|
||||
<ol data-sourcepos="5:7-6:18" class="task-list">
|
||||
<li data-sourcepos="5:7-5:22" class="task-list-item">
|
||||
<input type="checkbox" class="task-list-item-checkbox" checked disabled> task list</li>
|
||||
<li data-sourcepos="6:7-6:18" class="task-list-item">
|
||||
<input type="checkbox" class="task-list-item-checkbox" disabled> items</li>
|
||||
</ol>
|
||||
</li>
|
||||
</ol>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
- name: ordered_task_list_with_order
|
||||
markdown: |-
|
||||
4893. [x] hello
|
||||
4894. [x] world
|
||||
4895. [ ] example
|
||||
html: |-
|
||||
<ol start="4893" data-sourcepos="1:1-3:17" class="task-list" dir="auto">
|
||||
<li data-sourcepos="1:1-1:15" class="task-list-item">
|
||||
<input type="checkbox" class="task-list-item-checkbox" checked disabled> hello</li>
|
||||
<li data-sourcepos="2:1-2:15" class="task-list-item">
|
||||
<input type="checkbox" class="task-list-item-checkbox" checked disabled> world</li>
|
||||
<li data-sourcepos="3:1-3:17" class="task-list-item">
|
||||
<input type="checkbox" class="task-list-item-checkbox" disabled> example</li>
|
||||
</ol>
|
||||
|
||||
- name: reference_for_project_wiki
|
||||
api_context: project_wiki
|
||||
substitutions:
|
||||
# NOTE: We don't care about verifying specific attribute values here, that should be the
|
||||
# responsibility of unit tests. These tests are about the structure of the HTML.
|
||||
uri_substitution: *uri_substitution
|
||||
data_attribute_id_substitution:
|
||||
- regex: '(data-user|data-project|data-issue|data-iid|data-merge-request|data-milestone)(=")(\d+?)(")'
|
||||
replacement: '\1\2ID\4'
|
||||
text_attribute_substitution:
|
||||
- regex: '(title)(=")(.+?)(")'
|
||||
replacement: '\1\2TEXT\4'
|
||||
path_attribute_id_substitution:
|
||||
- regex: '(group|project)(\d+)'
|
||||
replacement: '\1ID'
|
||||
markdown: |-
|
||||
Hi @gfm_user - thank you for reporting this bug (#1) we hope to fix it in %1.1 as part of !1
|
||||
html: |-
|
||||
<p data-sourcepos="1:1-1:92" dir="auto">Hi <a href="/gfm_user" data-user="1" data-reference-type="user" data-container="body" data-placement="top" class="gfm gfm-project_member js-user-link" title="John Doe1">@gfm_user</a> - thank you for reporting this bug (<a href="/group1/project1/-/issues/1" data-original="#1" data-link="false" data-link-reference="false" data-project="11" data-issue="11" data-reference-type="issue" data-container="body" data-placement="top" title="My title 1" class="gfm gfm-issue has-tooltip">#1</a>) we hope to fix it in <a href="/group1/project1/-/milestones/1" data-original="%1.1" data-link="false" data-link-reference="false" data-project="11" data-milestone="11" data-reference-type="milestone" data-container="body" data-placement="top" title="" class="gfm gfm-milestone has-tooltip">%1.1</a> as part of <a href="/group1/project1/-/merge_requests/1" data-original="!1" data-link="false" data-link-reference="false" data-project="11" data-merge-request="11" data-project-path="group1/project1" data-iid="1" data-mr-title="My title 2" data-reference-type="merge_request" data-container="body" data-placement="top" title="" class="gfm gfm-merge_request">!1</a></p>
|
||||
- name: strike
|
||||
markdown: |-
|
||||
~~del~~
|
||||
html: |-
|
||||
<p data-sourcepos="1:1-1:7" dir="auto"><del>del</del></p>
|
||||
|
||||
- name: table
|
||||
markdown: |-
|
||||
| header | header |
|
||||
|--------|--------|
|
||||
| `code` | cell with **bold** |
|
||||
| ~~strike~~ | cell with _italic_ |
|
||||
|
||||
# content after table
|
||||
html: |-
|
||||
<table data-sourcepos="1:1-4:35" dir="auto">
|
||||
<thead>
|
||||
<tr data-sourcepos="1:1-1:19">
|
||||
<th data-sourcepos="1:2-1:9">header</th>
|
||||
<th data-sourcepos="1:11-1:18">header</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr data-sourcepos="3:1-3:31">
|
||||
<td data-sourcepos="3:2-3:9"><code>code</code></td>
|
||||
<td data-sourcepos="3:11-3:30">cell with <strong>bold</strong>
|
||||
</td>
|
||||
</tr>
|
||||
<tr data-sourcepos="4:1-4:35">
|
||||
<td data-sourcepos="4:2-4:13"><del>strike</del></td>
|
||||
<td data-sourcepos="4:15-4:34">cell with <em>italic</em>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h1 data-sourcepos="6:1-6:21" dir="auto">
|
||||
<a id="user-content-content-after-table" class="anchor" href="#content-after-table" aria-hidden="true"></a>content after table</h1>
|
||||
|
||||
- name: table_of_contents
|
||||
markdown: |-
|
||||
[[_TOC_]]
|
||||
|
||||
# Lorem
|
||||
|
||||
Well, that's just like... your opinion.. man.
|
||||
|
||||
## Ipsum
|
||||
|
||||
### Dolar
|
||||
|
||||
# Sit amit
|
||||
|
||||
### I don't know
|
||||
html: |-
|
||||
<ul class="section-nav">
|
||||
<li>
|
||||
<a href="#lorem">Lorem</a><ul><li>
|
||||
<a href="#ipsum">Ipsum</a><ul><li><a href="#dolar">Dolar</a></li></ul>
|
||||
</li></ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#sit-amit">Sit amit</a><ul><li><a href="#i-dont-know">I don't know</a></li></ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h1 data-sourcepos="3:1-3:7" dir="auto">
|
||||
<a id="user-content-lorem" class="anchor" href="#lorem" aria-hidden="true"></a>Lorem</h1>
|
||||
<p data-sourcepos="5:1-5:45" dir="auto">Well, that's just like... your opinion.. man.</p>
|
||||
<h2 data-sourcepos="7:1-7:8" dir="auto">
|
||||
<a id="user-content-ipsum" class="anchor" href="#ipsum" aria-hidden="true"></a>Ipsum</h2>
|
||||
<h3 data-sourcepos="9:1-9:9" dir="auto">
|
||||
<a id="user-content-dolar" class="anchor" href="#dolar" aria-hidden="true"></a>Dolar</h3>
|
||||
<h1 data-sourcepos="11:1-11:10" dir="auto">
|
||||
<a id="user-content-sit-amit" class="anchor" href="#sit-amit" aria-hidden="true"></a>Sit amit</h1>
|
||||
<h3 data-sourcepos="13:1-13:16" dir="auto">
|
||||
<a id="user-content-i-dont-know" class="anchor" href="#i-dont-know" aria-hidden="true"></a>I don't know</h3>
|
||||
|
||||
- name: task_list
|
||||
markdown: |-
|
||||
* [x] hello
|
||||
* [x] world
|
||||
* [ ] example
|
||||
* [ ] of nested
|
||||
* [x] task list
|
||||
* [ ] items
|
||||
html: |-
|
||||
<ul data-sourcepos="1:1-6:15" class="task-list" dir="auto">
|
||||
<li data-sourcepos="1:1-1:11" class="task-list-item">
|
||||
<input type="checkbox" class="task-list-item-checkbox" checked disabled> hello</li>
|
||||
<li data-sourcepos="2:1-2:11" class="task-list-item">
|
||||
<input type="checkbox" class="task-list-item-checkbox" checked disabled> world</li>
|
||||
<li data-sourcepos="3:1-6:15" class="task-list-item">
|
||||
<input type="checkbox" class="task-list-item-checkbox" disabled> example
|
||||
<ul data-sourcepos="4:3-6:15" class="task-list">
|
||||
<li data-sourcepos="4:3-6:15" class="task-list-item">
|
||||
<input type="checkbox" class="task-list-item-checkbox" disabled> of nested
|
||||
<ul data-sourcepos="5:5-6:15" class="task-list">
|
||||
<li data-sourcepos="5:5-5:19" class="task-list-item">
|
||||
<input type="checkbox" class="task-list-item-checkbox" checked disabled> task list</li>
|
||||
<li data-sourcepos="6:5-6:15" class="task-list-item">
|
||||
<input type="checkbox" class="task-list-item-checkbox" disabled> items</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
- name: video
|
||||
markdown: |-
|
||||
![Sample Video](https://gitlab.com/gitlab.mp4)
|
||||
html: |-
|
||||
<p data-sourcepos="1:1-1:46" dir="auto"><span class="media-container video-container"><video src="https://gitlab.com/gitlab.mp4" controls="true" data-setup="{}" data-title="Sample Video" width="400" preload="metadata"></video><a href="https://gitlab.com/gitlab.mp4" target="_blank" rel="nofollow noreferrer noopener" title="Download 'Sample Video'">Sample Video</a></span></p>
|
||||
|
||||
- name: word_break
|
||||
markdown: Fernstraßen<wbr>bau<wbr>privat<wbr>finanzierungs<wbr>gesetz
|
||||
html: <p data-sourcepos="1:1-1:60" dir="auto">Fernstraßen<wbr>bau<wbr>privat<wbr>finanzierungs<wbr>gesetz</wbr></wbr></wbr></wbr></p>
|
|
@ -1,27 +0,0 @@
|
|||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import jsYaml from 'js-yaml';
|
||||
// eslint-disable-next-line import/no-deprecated
|
||||
import { getJSONFixture } from 'helpers/fixtures';
|
||||
|
||||
export const loadMarkdownApiResult = (testName) => {
|
||||
const fixturePathPrefix = `api/markdown/${testName}.json`;
|
||||
|
||||
// eslint-disable-next-line import/no-deprecated
|
||||
const fixture = getJSONFixture(fixturePathPrefix);
|
||||
return fixture.body || fixture.html;
|
||||
};
|
||||
|
||||
export const loadMarkdownApiExamples = () => {
|
||||
const apiMarkdownYamlPath = path.join(__dirname, '..', 'fixtures', 'api_markdown.yml');
|
||||
const apiMarkdownYamlText = fs.readFileSync(apiMarkdownYamlPath);
|
||||
const apiMarkdownExampleObjects = jsYaml.safeLoad(apiMarkdownYamlText);
|
||||
|
||||
return apiMarkdownExampleObjects.map(({ name, context, markdown }) => [name, context, markdown]);
|
||||
};
|
||||
|
||||
export const loadMarkdownApiExample = (testName) => {
|
||||
return loadMarkdownApiExamples().find(([name, context]) => {
|
||||
return (context ? `${context}_${name}` : name) === testName;
|
||||
})[2];
|
||||
};
|
|
@ -1,20 +1,19 @@
|
|||
import { createContentEditor } from '~/content_editor';
|
||||
import { loadMarkdownApiExamples, loadMarkdownApiResult } from './markdown_processing_examples';
|
||||
import path from 'path';
|
||||
import { createSharedExamples, loadMarkdownApiExamples } from './markdown_processing_spec_helper';
|
||||
|
||||
jest.mock('~/emoji');
|
||||
|
||||
describe('markdown processing', () => {
|
||||
// See spec/fixtures/markdown/markdown_golden_master_examples.yml for documentation on how this spec works.
|
||||
describe('markdown processing in ContentEditor', () => {
|
||||
// Ensure we generate same markdown that was provided to Markdown API.
|
||||
it.each(loadMarkdownApiExamples())(
|
||||
'correctly handles %s (context: %s)',
|
||||
async (name, context, markdown) => {
|
||||
const testName = context ? `${context}_${name}` : name;
|
||||
const contentEditor = createContentEditor({
|
||||
renderMarkdown: () => loadMarkdownApiResult(testName),
|
||||
});
|
||||
await contentEditor.setSerializedContent(markdown);
|
||||
|
||||
expect(contentEditor.getSerializedContent()).toBe(markdown);
|
||||
},
|
||||
const markdownYamlPath = path.join(
|
||||
__dirname,
|
||||
'..',
|
||||
'..',
|
||||
'fixtures',
|
||||
'markdown',
|
||||
'markdown_golden_master_examples.yml',
|
||||
);
|
||||
// eslint-disable-next-line jest/valid-describe
|
||||
describe.each(loadMarkdownApiExamples(markdownYamlPath))('%s', createSharedExamples);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
import fs from 'fs';
|
||||
import jsYaml from 'js-yaml';
|
||||
import { memoize } from 'lodash';
|
||||
import { createContentEditor } from '~/content_editor';
|
||||
import { setTestTimeoutOnce } from 'helpers/timeout';
|
||||
|
||||
const getFocusedMarkdownExamples = memoize(
|
||||
() => process.env.FOCUSED_MARKDOWN_EXAMPLES?.split(',') || [],
|
||||
);
|
||||
|
||||
const includeExample = ({ name }) => {
|
||||
const focusedMarkdownExamples = getFocusedMarkdownExamples();
|
||||
if (!focusedMarkdownExamples.length) {
|
||||
return true;
|
||||
}
|
||||
return focusedMarkdownExamples.includes(name);
|
||||
};
|
||||
|
||||
const getPendingReason = (pendingStringOrObject) => {
|
||||
if (!pendingStringOrObject) {
|
||||
return null;
|
||||
}
|
||||
if (typeof pendingStringOrObject === 'string') {
|
||||
return pendingStringOrObject;
|
||||
}
|
||||
if (pendingStringOrObject.frontend) {
|
||||
return pendingStringOrObject.frontend;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line jest/no-export
|
||||
export const loadMarkdownApiExamples = (markdownYamlPath) => {
|
||||
const apiMarkdownYamlText = fs.readFileSync(markdownYamlPath);
|
||||
const apiMarkdownExampleObjects = jsYaml.safeLoad(apiMarkdownYamlText);
|
||||
|
||||
return apiMarkdownExampleObjects
|
||||
.filter(includeExample)
|
||||
.map(({ name, pending, markdown, html }) => [
|
||||
name,
|
||||
{ pendingReason: getPendingReason(pending), markdown, html },
|
||||
]);
|
||||
};
|
||||
|
||||
const testSerializesHtmlToMarkdownForElement = async ({ markdown, html }) => {
|
||||
const contentEditor = createContentEditor({
|
||||
// Overwrite renderMarkdown to always return this specific html
|
||||
renderMarkdown: () => html,
|
||||
});
|
||||
|
||||
await contentEditor.setSerializedContent(markdown);
|
||||
|
||||
// This serializes the ContentEditor document, which was based on the HTML, to markdown
|
||||
const serializedContent = contentEditor.getSerializedContent();
|
||||
|
||||
// Assert that the markdown we ended up with after sending it through all the ContentEditor
|
||||
// plumbing matches the original markdown from the YAML.
|
||||
expect(serializedContent).toBe(markdown);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line jest/no-export
|
||||
export const createSharedExamples = (name, { pendingReason, ...example }) => {
|
||||
const exampleName = 'correctly serializes HTML to markdown';
|
||||
if (pendingReason) {
|
||||
it.todo(`${exampleName}: ${pendingReason}`);
|
||||
} else {
|
||||
it(exampleName, async () => {
|
||||
if (name === 'frontmatter_toml') {
|
||||
setTestTimeoutOnce(2000);
|
||||
}
|
||||
await testSerializesHtmlToMarkdownForElement(example);
|
||||
});
|
||||
}
|
||||
};
|
|
@ -1,65 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe API::MergeRequests, '(JavaScript fixtures)', type: :request do
|
||||
include ApiHelpers
|
||||
include WikiHelpers
|
||||
include JavaScriptFixturesHelpers
|
||||
|
||||
let_it_be(:user) { create(:user, username: 'gitlab') }
|
||||
|
||||
let_it_be(:group) { create(:group, :public) }
|
||||
let_it_be(:project) { create(:project, :public, :repository, group: group) }
|
||||
|
||||
let_it_be(:label) { create(:label, project: project, title: 'bug') }
|
||||
let_it_be(:milestone) { create(:milestone, project: project, title: '1.1') }
|
||||
let_it_be(:issue) { create(:issue, project: project) }
|
||||
let_it_be(:merge_request) { create(:merge_request, source_project: project) }
|
||||
|
||||
let_it_be(:project_wiki) { create(:project_wiki, project: project, user: user) }
|
||||
|
||||
let(:project_wiki_page) { create(:wiki_page, wiki: project_wiki) }
|
||||
|
||||
before(:all) do
|
||||
group.add_owner(user)
|
||||
project.add_maintainer(user)
|
||||
end
|
||||
|
||||
before do
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
markdown_examples = begin
|
||||
yaml_file_path = File.expand_path('api_markdown.yml', __dir__)
|
||||
yaml = File.read(yaml_file_path)
|
||||
YAML.safe_load(yaml, symbolize_names: true)
|
||||
end
|
||||
|
||||
markdown_examples.each do |markdown_example|
|
||||
context = markdown_example.fetch(:context, '')
|
||||
name = markdown_example.fetch(:name)
|
||||
|
||||
context "for #{name}#{!context.empty? ? " (context: #{context})" : ''}" do
|
||||
let(:markdown) { markdown_example.fetch(:markdown) }
|
||||
|
||||
name = "#{context}_#{name}" unless context.empty?
|
||||
|
||||
it "api/markdown/#{name}.json" do
|
||||
api_url = case context
|
||||
when 'project'
|
||||
"/#{project.full_path}/preview_markdown"
|
||||
when 'group'
|
||||
"/groups/#{group.full_path}/preview_markdown"
|
||||
when 'project_wiki'
|
||||
"/#{project.full_path}/-/wikis/#{project_wiki_page.slug}/preview_markdown"
|
||||
else
|
||||
api "/markdown"
|
||||
end
|
||||
|
||||
post api_url, params: { text: markdown, gfm: true }
|
||||
expect(response).to be_successful
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,289 +0,0 @@
|
|||
# This data file drives the specs in
|
||||
# spec/frontend/fixtures/api_markdown.rb and
|
||||
# spec/frontend/content_editor/extensions/markdown_processing_spec.js
|
||||
---
|
||||
- name: attachment_image
|
||||
context: group
|
||||
markdown: '![test-file](/uploads/aa45a38ec2cfe97433281b10bbff042c/test-file.png)'
|
||||
- name: attachment_image
|
||||
context: project
|
||||
markdown: '![test-file](/uploads/aa45a38ec2cfe97433281b10bbff042c/test-file.png)'
|
||||
- name: attachment_image
|
||||
context: project_wiki
|
||||
markdown: '![test-file](test-file.png)'
|
||||
- name: attachment_link
|
||||
context: group
|
||||
markdown: '[test-file](/uploads/aa45a38ec2cfe97433281b10bbff042c/test-file.zip)'
|
||||
- name: attachment_link
|
||||
context: project
|
||||
markdown: '[test-file](/uploads/aa45a38ec2cfe97433281b10bbff042c/test-file.zip)'
|
||||
- name: attachment_link
|
||||
context: project_wiki
|
||||
markdown: '[test-file](test-file.zip)'
|
||||
- name: audio
|
||||
markdown: '![Sample Audio](https://gitlab.com/gitlab.mp3)'
|
||||
- name: audio_and_video_in_lists
|
||||
markdown: |-
|
||||
* ![Sample Audio](https://gitlab.com/1.mp3)
|
||||
* ![Sample Video](https://gitlab.com/2.mp4)
|
||||
|
||||
1. ![Sample Video](https://gitlab.com/1.mp4)
|
||||
2. ![Sample Audio](https://gitlab.com/2.mp3)
|
||||
|
||||
* [x] ![Sample Audio](https://gitlab.com/1.mp3)
|
||||
* [x] ![Sample Audio](https://gitlab.com/2.mp3)
|
||||
* [x] ![Sample Video](https://gitlab.com/3.mp4)
|
||||
- name: blockquote
|
||||
markdown: |-
|
||||
> This is a blockquote
|
||||
>
|
||||
> This is another one
|
||||
- name: bold
|
||||
markdown: '**bold**'
|
||||
- name: bullet_list_style_1
|
||||
markdown: |-
|
||||
* list item 1
|
||||
* list item 2
|
||||
* embedded list item 3
|
||||
- name: bullet_list_style_2
|
||||
markdown: |-
|
||||
- list item 1
|
||||
- list item 2
|
||||
* embedded list item 3
|
||||
- name: bullet_list_style_3
|
||||
markdown: |-
|
||||
+ list item 1
|
||||
+ list item 2
|
||||
- embedded list item 3
|
||||
- name: code_block
|
||||
markdown: |-
|
||||
```javascript
|
||||
console.log('hello world')
|
||||
```
|
||||
- name: color_chips
|
||||
markdown: |-
|
||||
- `#F00`
|
||||
- `#F00A`
|
||||
- `#FF0000`
|
||||
- `#FF0000AA`
|
||||
- `RGB(0,255,0)`
|
||||
- `RGB(0%,100%,0%)`
|
||||
- `RGBA(0,255,0,0.3)`
|
||||
- `HSL(540,70%,50%)`
|
||||
- `HSLA(540,70%,50%,0.3)`
|
||||
- name: description_list
|
||||
markdown: |-
|
||||
<dl>
|
||||
<dt>Frog</dt>
|
||||
<dd>Wet green thing</dd>
|
||||
<dt>Rabbit</dt>
|
||||
<dd>Warm fluffy thing</dd>
|
||||
<dt>Punt</dt>
|
||||
<dd>Kick a ball</dd>
|
||||
<dd>Take a bet</dd>
|
||||
<dt>Color</dt>
|
||||
<dt>Colour</dt>
|
||||
<dd>
|
||||
|
||||
Any hue except _white_ or **black**
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
- name: details
|
||||
markdown: |-
|
||||
<details>
|
||||
<summary>Apply this patch</summary>
|
||||
|
||||
```diff
|
||||
diff --git a/spec/frontend/fixtures/api_markdown.yml b/spec/frontend/fixtures/api_markdown.yml
|
||||
index 8433efaf00c..69b12c59d46 100644
|
||||
--- a/spec/frontend/fixtures/api_markdown.yml
|
||||
+++ b/spec/frontend/fixtures/api_markdown.yml
|
||||
@@ -33,6 +33,13 @@
|
||||
* <ruby>漢<rt>ㄏㄢˋ</rt></ruby>
|
||||
* C<sub>7</sub>H<sub>16</sub> + O<sub>2</sub> → CO<sub>2</sub> + H<sub>2</sub>O
|
||||
* The **Pythagorean theorem** is often expressed as <var>a<sup>2</sup></var> + <var>b<sup>2</sup></var> = <var>c<sup>2</sup></var>.The **Pythagorean theorem** is often expressed as <var>a<sup>2</sup></var> + <var>b<sup>2</sup></var> = <var>c<sup>2</sup></var>
|
||||
+- name: details
|
||||
+ markdown: |-
|
||||
+ <details>
|
||||
+ <summary>Apply this patch</summary>
|
||||
+
|
||||
+ 🐶 much meta, 🐶 many patch
|
||||
+ 🐶 such diff, 🐶 very meme
|
||||
+ 🐶 wow!
|
||||
+ </details>
|
||||
- name: link
|
||||
markdown: '[GitLab](https://gitlab.com)'
|
||||
- name: attachment_link
|
||||
```
|
||||
|
||||
</details>
|
||||
- name: div
|
||||
markdown: |-
|
||||
<div>plain text</div>
|
||||
<div>
|
||||
|
||||
just a plain ol' div, not much to _expect_!
|
||||
|
||||
</div>
|
||||
- name: emoji
|
||||
markdown: ':sparkles: :heart: :100:'
|
||||
- name: emphasis
|
||||
markdown: '_emphasized text_'
|
||||
- name: figure
|
||||
markdown: |-
|
||||
<figure>
|
||||
|
||||
![Elephant at sunset](elephant-sunset.jpg)
|
||||
|
||||
<figcaption>An elephant at sunset</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
|
||||
![A crocodile wearing crocs](croc-crocs.jpg)
|
||||
|
||||
<figcaption>
|
||||
|
||||
A crocodile wearing _crocs_!
|
||||
|
||||
</figcaption>
|
||||
</figure>
|
||||
- name: frontmatter_json
|
||||
markdown: |-
|
||||
;;;
|
||||
{
|
||||
"title": "Page title"
|
||||
}
|
||||
;;;
|
||||
- name: frontmatter_toml
|
||||
markdown: |-
|
||||
+++
|
||||
title = "Page title"
|
||||
+++
|
||||
- name: frontmatter_yaml
|
||||
markdown: |-
|
||||
---
|
||||
title: Page title
|
||||
---
|
||||
- name: hard_break
|
||||
markdown: |-
|
||||
This is a line after a\
|
||||
hard break
|
||||
- name: headings
|
||||
markdown: |-
|
||||
# Heading 1
|
||||
|
||||
## Heading 2
|
||||
|
||||
### Heading 3
|
||||
|
||||
#### Heading 4
|
||||
|
||||
##### Heading 5
|
||||
|
||||
###### Heading 6
|
||||
- name: horizontal_rule
|
||||
markdown: '---'
|
||||
- name: html_marks
|
||||
markdown: |-
|
||||
* Content editor is ~~great~~<ins>amazing</ins>.
|
||||
* If the changes <abbr title="Looks good to merge">LGTM</abbr>, please <abbr title="Merge when pipeline succeeds">MWPS</abbr>.
|
||||
* The English song <q>Oh I do like to be beside the seaside</q> looks like this in Hebrew: <span dir="rtl">אה, אני אוהב להיות ליד חוף הים</span>. In the computer's memory, this is stored as <bdo dir="ltr">אה, אני אוהב להיות ליד חוף הים</bdo>.
|
||||
* <cite>The Scream</cite> by Edvard Munch. Painted in 1893.
|
||||
* <dfn>HTML</dfn> is the standard markup language for creating web pages.
|
||||
* Do not forget to buy <mark>milk</mark> today.
|
||||
* This is a paragraph and <small>smaller text goes here</small>.
|
||||
* The concert starts at <time datetime="20:00">20:00</time> and you'll be able to enjoy the band for at least <time datetime="PT2H30M">2h 30m</time>.
|
||||
* Press <kbd>Ctrl</kbd> + <kbd>C</kbd> to copy text (Windows).
|
||||
* WWF's goal is to: <q>Build a future where people live in harmony with nature.</q> We hope they succeed.
|
||||
* The error occured was: <samp>Keyboard not found. Press F1 to continue.</samp>
|
||||
* The area of a triangle is: 1/2 x <var>b</var> x <var>h</var>, where <var>b</var> is the base, and <var>h</var> is the vertical height.
|
||||
* <ruby>漢<rt>ㄏㄢˋ</rt></ruby>
|
||||
* C<sub>7</sub>H<sub>16</sub> + O<sub>2</sub> → CO<sub>2</sub> + H<sub>2</sub>O
|
||||
* The **Pythagorean theorem** is often expressed as <var>a<sup>2</sup></var> + <var>b<sup>2</sup></var> = <var>c<sup>2</sup></var>
|
||||
- name: image
|
||||
markdown: '![alt text](https://gitlab.com/logo.png)'
|
||||
- name: inline_code
|
||||
markdown: '`code`'
|
||||
- name: inline_diff
|
||||
markdown: |-
|
||||
* {-deleted-}
|
||||
* {+added+}
|
||||
- name: link
|
||||
markdown: '[GitLab](https://gitlab.com)'
|
||||
- name: math
|
||||
markdown: |-
|
||||
This math is inline $`a^2+b^2=c^2`$.
|
||||
|
||||
This is on a separate line:
|
||||
|
||||
```math
|
||||
a^2+b^2=c^2
|
||||
```
|
||||
- name: ordered_list
|
||||
markdown: |-
|
||||
1. list item 1
|
||||
2. list item 2
|
||||
3. list item 3
|
||||
- name: ordered_list_with_start_order
|
||||
markdown: |-
|
||||
134. list item 1
|
||||
135. list item 2
|
||||
136. list item 3
|
||||
- name: ordered_task_list
|
||||
markdown: |-
|
||||
1. [x] hello
|
||||
2. [x] world
|
||||
3. [ ] example
|
||||
1. [ ] of nested
|
||||
1. [x] task list
|
||||
2. [ ] items
|
||||
- name: ordered_task_list_with_order
|
||||
markdown: |-
|
||||
4893. [x] hello
|
||||
4894. [x] world
|
||||
4895. [ ] example
|
||||
- name: reference
|
||||
context: project_wiki
|
||||
markdown: |-
|
||||
Hi @gitlab - thank you for reporting this ~bug (#1) we hope to fix it in %1.1 as part of !1
|
||||
- name: strike
|
||||
markdown: '~~del~~'
|
||||
- name: table
|
||||
markdown: |-
|
||||
| header | header |
|
||||
|--------|--------|
|
||||
| `code` | cell with **bold** |
|
||||
| ~~strike~~ | cell with _italic_ |
|
||||
|
||||
# content after table
|
||||
- name: table_of_contents
|
||||
markdown: |-
|
||||
[[_TOC_]]
|
||||
|
||||
# Lorem
|
||||
|
||||
Well, that's just like... your opinion.. man.
|
||||
|
||||
## Ipsum
|
||||
|
||||
### Dolar
|
||||
|
||||
# Sit amit
|
||||
|
||||
### I don't know
|
||||
- name: task_list
|
||||
markdown: |-
|
||||
* [x] hello
|
||||
* [x] world
|
||||
* [ ] example
|
||||
* [ ] of nested
|
||||
* [x] task list
|
||||
* [ ] items
|
||||
- name: thematic_break
|
||||
markdown: |-
|
||||
---
|
||||
- name: video
|
||||
markdown: '![Sample Video](https://gitlab.com/gitlab.mp4)'
|
||||
- name: word_break
|
||||
markdown: Fernstraßen<wbr>bau<wbr>privat<wbr>finanzierungs<wbr>gesetz
|
9
spec/requests/api/markdown_golden_master_spec.rb
Normal file
9
spec/requests/api/markdown_golden_master_spec.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
# See spec/fixtures/markdown/markdown_golden_master_examples.yml for documentation on how this spec works.
|
||||
RSpec.describe API::Markdown, 'Golden Master' do
|
||||
markdown_yml_file_path = File.expand_path('../../fixtures/markdown/markdown_golden_master_examples.yml', __dir__)
|
||||
include_context 'API::Markdown Golden Master shared context', markdown_yml_file_path
|
||||
end
|
|
@ -112,7 +112,7 @@ RSpec.describe RuboCop::Cop::StaticTranslationDefinition do
|
|||
}
|
||||
end
|
||||
CODE
|
||||
<<~CODE
|
||||
<<~CODE,
|
||||
class MyClass
|
||||
def hello
|
||||
{
|
||||
|
@ -121,6 +121,20 @@ RSpec.describe RuboCop::Cop::StaticTranslationDefinition do
|
|||
end
|
||||
end
|
||||
CODE
|
||||
<<~CODE,
|
||||
SomeClass = Struct.new do
|
||||
def text
|
||||
_('Some translated text')
|
||||
end
|
||||
end
|
||||
CODE
|
||||
<<~CODE
|
||||
Struct.new('SomeClass') do
|
||||
def text
|
||||
_('Some translated text')
|
||||
end
|
||||
end
|
||||
CODE
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
@ -450,6 +450,13 @@ RSpec.configure do |config|
|
|||
$stdout = StringIO.new
|
||||
end
|
||||
|
||||
# Makes diffs show entire non-truncated values.
|
||||
config.before(:each, unlimited_max_formatted_output_length: true) do |_example|
|
||||
config.expect_with :rspec do |c|
|
||||
c.max_formatted_output_length = nil
|
||||
end
|
||||
end
|
||||
|
||||
config.after(:each, :silence_stdout) do
|
||||
$stdout = STDOUT
|
||||
end
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
# See spec/fixtures/markdown/markdown_golden_master_examples.yml for documentation on how this spec works.
|
||||
RSpec.shared_context 'API::Markdown Golden Master shared context' do |markdown_yml_file_path|
|
||||
include ApiHelpers
|
||||
include WikiHelpers
|
||||
|
||||
let_it_be(:user) { create(:user, username: 'gfm_user') }
|
||||
|
||||
let_it_be(:group) { create(:group, :public) }
|
||||
let_it_be(:project) { create(:project, :public, :repository, group: group) }
|
||||
|
||||
let_it_be(:label) { create(:label, project: project, title: 'bug') }
|
||||
let_it_be(:milestone) { create(:milestone, project: project, title: '1.1') }
|
||||
let_it_be(:issue) { create(:issue, project: project) }
|
||||
let_it_be(:merge_request) { create(:merge_request, source_project: project) }
|
||||
|
||||
let_it_be(:project_wiki) { create(:project_wiki, project: project, user: user) }
|
||||
|
||||
let_it_be(:project_wiki_page) { create(:wiki_page, wiki: project_wiki) }
|
||||
|
||||
before(:all) do
|
||||
group.add_owner(user)
|
||||
project.add_maintainer(user)
|
||||
end
|
||||
|
||||
before do
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
markdown_examples = begin
|
||||
yaml = File.read(markdown_yml_file_path)
|
||||
YAML.safe_load(yaml, symbolize_names: true, aliases: true)
|
||||
end
|
||||
|
||||
it "examples must be unique and alphabetized by name", :unlimited_max_formatted_output_length do
|
||||
names = markdown_examples.map { |example| example[:name] }
|
||||
expect(names).to eq(names.sort.uniq)
|
||||
end
|
||||
|
||||
if focused_markdown_examples_string = ENV['FOCUSED_MARKDOWN_EXAMPLES']
|
||||
focused_markdown_examples = focused_markdown_examples_string.split(',').map(&:strip) || []
|
||||
markdown_examples.reject! {|markdown_example| !focused_markdown_examples.include?(markdown_example.fetch(:name)) }
|
||||
end
|
||||
|
||||
markdown_examples.each do |markdown_example|
|
||||
name = markdown_example.fetch(:name)
|
||||
api_context = markdown_example[:api_context]
|
||||
|
||||
if api_context && !name.end_with?("_for_#{api_context}")
|
||||
raise "Name must have suffix of '_for_#{api_context}' to the api_context"
|
||||
end
|
||||
|
||||
context "for #{name}#{api_context ? " (api_context: #{api_context})" : ''}" do
|
||||
let(:pending_reason) do
|
||||
pending_value = markdown_example.fetch(:pending, nil)
|
||||
get_pending_reason(pending_value)
|
||||
end
|
||||
|
||||
let(:example_markdown) { markdown_example.fetch(:markdown) }
|
||||
let(:example_html) { markdown_example.fetch(:html) }
|
||||
let(:substitutions) { markdown_example.fetch(:substitutions, {}) }
|
||||
|
||||
it "verifies conversion of GFM to HTML", :unlimited_max_formatted_output_length do
|
||||
pending pending_reason if pending_reason
|
||||
|
||||
normalized_example_html = normalize_html(example_html, substitutions)
|
||||
|
||||
api_url = get_url_for_api_context(api_context)
|
||||
|
||||
post api_url, params: { text: example_markdown, gfm: true }
|
||||
expect(response).to be_successful
|
||||
response_body = Gitlab::Json.parse(response.body)
|
||||
# Some requests have the HTML in the `html` key, others in the `body` key.
|
||||
response_html = response_body['body'] ? response_body.fetch('body') : response_body.fetch('html')
|
||||
normalized_response_html = normalize_html(response_html, substitutions)
|
||||
|
||||
expect(normalized_response_html).to eq(normalized_example_html)
|
||||
end
|
||||
|
||||
def get_pending_reason(pending_value)
|
||||
return false unless pending_value
|
||||
|
||||
return pending_value if pending_value.is_a?(String)
|
||||
|
||||
pending_value[:backend] || false
|
||||
end
|
||||
|
||||
def normalize_html(html, substitutions)
|
||||
normalized_html = html.dup
|
||||
# Note: having the top level `substitutions` data structure be a hash of arrays
|
||||
# allows us to compose multiple substitutions via YAML anchors (YAML anchors
|
||||
# pointing to arrays can't be combined)
|
||||
substitutions.each_value do |substitution_entry|
|
||||
substitution_entry.each do |substitution|
|
||||
regex = substitution.fetch(:regex)
|
||||
replacement = substitution.fetch(:replacement)
|
||||
normalized_html.gsub!(%r{#{regex}}, replacement)
|
||||
end
|
||||
end
|
||||
|
||||
normalized_html
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def supported_api_contexts
|
||||
%w(project group project_wiki)
|
||||
end
|
||||
|
||||
def get_url_for_api_context(api_context)
|
||||
case api_context
|
||||
when 'project'
|
||||
"/#{project.full_path}/preview_markdown"
|
||||
when 'group'
|
||||
"/groups/#{group.full_path}/preview_markdown"
|
||||
when 'project_wiki'
|
||||
"/#{project.full_path}/-/wikis/#{project_wiki_page.slug}/preview_markdown"
|
||||
when nil
|
||||
api "/markdown"
|
||||
else
|
||||
raise "Error: 'context' extension was '#{api_context}'. It must be one of: #{supported_api_contexts.join(',')}"
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue