Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
3a0d395c
Commit
3a0d395c
authored
Jun 16, 2021
by
Himanshu Kapoor
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add tests for various contexts in content editor
parent
74d83dec
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
135 additions
and
25 deletions
+135
-25
app/assets/javascripts/content_editor/components/toolbar_link_button.vue
...scripts/content_editor/components/toolbar_link_button.vue
+11
-3
app/assets/javascripts/content_editor/extensions/link.js
app/assets/javascripts/content_editor/extensions/link.js
+30
-3
spec/frontend/content_editor/components/toolbar_link_button_spec.js
...end/content_editor/components/toolbar_link_button_spec.js
+34
-9
spec/frontend/content_editor/markdown_processing_examples.js
spec/frontend/content_editor/markdown_processing_examples.js
+1
-2
spec/frontend/content_editor/markdown_processing_spec.js
spec/frontend/content_editor/markdown_processing_spec.js
+10
-6
spec/frontend/fixtures/api_markdown.rb
spec/frontend/fixtures/api_markdown.rb
+37
-2
spec/frontend/fixtures/api_markdown.yml
spec/frontend/fixtures/api_markdown.yml
+12
-0
No files found.
app/assets/javascripts/content_editor/components/toolbar_link_button.vue
View file @
3a0d395c
...
...
@@ -43,14 +43,22 @@ export default {
},
mounted
()
{
this
.
tiptapEditor
.
on
(
'
selectionUpdate
'
,
({
editor
})
=>
{
const
{
href
}
=
editor
.
getAttributes
(
linkContentType
);
const
{
'
data-canonical-src
'
:
canonicalSrc
,
href
}
=
editor
.
getAttributes
(
linkContentType
);
this
.
linkHref
=
href
;
this
.
linkHref
=
canonicalSrc
||
href
;
});
},
methods
:
{
updateLink
()
{
this
.
tiptapEditor
.
chain
().
focus
().
unsetLink
().
setLink
({
href
:
this
.
linkHref
}).
run
();
this
.
tiptapEditor
.
chain
()
.
focus
()
.
unsetLink
()
.
setLink
({
href
:
this
.
linkHref
,
'
data-canonical-src
'
:
this
.
linkHref
,
})
.
run
();
this
.
$emit
(
'
execute
'
,
{
contentType
:
linkContentType
});
},
...
...
app/assets/javascripts/content_editor/extensions/link.js
View file @
3a0d395c
import
{
markInputRule
}
from
'
@tiptap/core
'
;
import
{
Link
}
from
'
@tiptap/extension-link
'
;
import
{
defaultMarkdownSerializer
}
from
'
prosemirror-markdown/src/to_markdown
'
;
export
const
markdownLinkSyntaxInputRuleRegExp
=
/
(?:
^|
\s)\[([\w
|
\s
|-
]
+
)\]\((?<
href>.+
?)\)
$/gm
;
export
const
urlSyntaxRegExp
=
/
(?:
^|
\s)(?<
href>
(?:
https
?
:
\/\/
|www
\.)[\S]
+
)(?:\s
|
\n)
$/gim
;
const
extractHrefFromMatch
=
(
match
)
=>
{
...
...
@@ -29,8 +27,37 @@ export const tiptapExtension = Link.extend({
markInputRule
(
urlSyntaxRegExp
,
this
.
type
,
extractHrefFromMatch
),
];
},
addAttributes
()
{
return
{
...
this
.
parent
?.(),
href
:
{
default
:
null
,
parseHTML
:
(
element
)
=>
{
return
{
href
:
element
.
getAttribute
(
'
href
'
),
};
},
},
'
data-canonical-src
'
:
{
default
:
null
,
parseHTML
:
(
element
)
=>
{
return
{
href
:
element
.
dataset
.
canonicalSrc
,
};
},
},
};
},
}).
configure
({
openOnClick
:
false
,
});
export
const
serializer
=
defaultMarkdownSerializer
.
marks
.
link
;
export
const
serializer
=
{
open
()
{
return
'
[
'
;
},
close
(
state
,
mark
)
{
const
href
=
mark
.
attrs
[
'
data-canonical-src
'
]
||
mark
.
attrs
.
href
;
return
`](
${
state
.
esc
(
href
)}${
mark
.
attrs
.
title
?
`
${
state
.
quote
(
mark
.
attrs
.
title
)}
`
:
''
}
)`
;
},
};
spec/frontend/content_editor/components/toolbar_link_button_spec.js
View file @
3a0d395c
import
{
GlDropdown
,
GlDropdownDivider
,
Gl
FormInputGroup
,
GlButton
}
from
'
@gitlab/ui
'
;
import
{
GlDropdown
,
GlDropdownDivider
,
Gl
Button
,
GlFormInputGroup
}
from
'
@gitlab/ui
'
;
import
{
mountExtended
}
from
'
helpers/vue_test_utils_helper
'
;
import
ToolbarLinkButton
from
'
~/content_editor/components/toolbar_link_button.vue
'
;
import
{
tiptapExtension
as
Link
}
from
'
~/content_editor/extensions/link
'
;
...
...
@@ -16,9 +16,6 @@ describe('content_editor/components/toolbar_link_button', () => {
propsData
:
{
tiptapEditor
:
editor
,
},
stubs
:
{
GlFormInputGroup
,
},
});
};
const
findDropdown
=
()
=>
wrapper
.
findComponent
(
GlDropdown
);
...
...
@@ -45,9 +42,8 @@ describe('content_editor/components/toolbar_link_button', () => {
});
describe
(
'
when there is an active link
'
,
()
=>
{
beforeEach
(()
=>
{
jest
.
spyOn
(
editor
,
'
isActive
'
);
editor
.
isActive
.
mockReturnValueOnce
(
true
);
beforeEach
(
async
()
=>
{
jest
.
spyOn
(
editor
,
'
isActive
'
).
mockReturnValueOnce
(
true
);
buildWrapper
();
});
...
...
@@ -78,9 +74,35 @@ describe('content_editor/components/toolbar_link_button', () => {
expect
(
commands
.
focus
).
toHaveBeenCalled
();
expect
(
commands
.
unsetLink
).
toHaveBeenCalled
();
expect
(
commands
.
setLink
).
toHaveBeenCalledWith
({
href
:
'
https://example
'
});
expect
(
commands
.
setLink
).
toHaveBeenCalledWith
({
href
:
'
https://example
'
,
'
data-canonical-src
'
:
'
https://example
'
,
});
expect
(
commands
.
run
).
toHaveBeenCalled
();
});
describe
(
'
on selection update
'
,
()
=>
{
it
(
'
updates link input box with canonical-src if present
'
,
async
()
=>
{
jest
.
spyOn
(
editor
,
'
getAttributes
'
).
mockReturnValueOnce
({
'
data-canonical-src
'
:
'
uploads/my-file.zip
'
,
href
:
'
/username/my-project/uploads/abcdefgh133535/my-file.zip
'
,
});
await
editor
.
emit
(
'
selectionUpdate
'
,
{
editor
});
expect
(
findLinkURLInput
().
element
.
value
).
toEqual
(
'
uploads/my-file.zip
'
);
});
it
(
'
updates link input box with link href otherwise
'
,
async
()
=>
{
jest
.
spyOn
(
editor
,
'
getAttributes
'
).
mockReturnValueOnce
({
href
:
'
https://gitlab.com
'
,
});
await
editor
.
emit
(
'
selectionUpdate
'
,
{
editor
});
expect
(
findLinkURLInput
().
element
.
value
).
toEqual
(
'
https://gitlab.com
'
);
});
});
});
describe
(
'
when there is not an active link
'
,
()
=>
{
...
...
@@ -106,7 +128,10 @@ describe('content_editor/components/toolbar_link_button', () => {
await
findApplyLinkButton
().
trigger
(
'
click
'
);
expect
(
commands
.
focus
).
toHaveBeenCalled
();
expect
(
commands
.
setLink
).
toHaveBeenCalledWith
({
href
:
'
https://example
'
});
expect
(
commands
.
setLink
).
toHaveBeenCalledWith
({
href
:
'
https://example
'
,
'
data-canonical-src
'
:
'
https://example
'
,
});
expect
(
commands
.
run
).
toHaveBeenCalled
();
});
});
...
...
spec/frontend/content_editor/markdown_processing_examples.js
View file @
3a0d395c
import
fs
from
'
fs
'
;
import
path
from
'
path
'
;
import
jsYaml
from
'
js-yaml
'
;
import
{
toArray
}
from
'
lodash
'
;
import
{
getJSONFixture
}
from
'
helpers/fixtures
'
;
export
const
loadMarkdownApiResult
=
(
testName
)
=>
{
...
...
@@ -15,5 +14,5 @@ export const loadMarkdownApiExamples = () => {
const
apiMarkdownYamlText
=
fs
.
readFileSync
(
apiMarkdownYamlPath
);
const
apiMarkdownExampleObjects
=
jsYaml
.
safeLoad
(
apiMarkdownYamlText
);
return
apiMarkdownExampleObjects
.
map
((
example
)
=>
toArray
(
example
)
);
return
apiMarkdownExampleObjects
.
map
((
{
name
,
context
,
markdown
})
=>
[
name
,
context
,
markdown
]
);
};
spec/frontend/content_editor/markdown_processing_spec.js
View file @
3a0d395c
...
...
@@ -3,11 +3,15 @@ import { loadMarkdownApiExamples, loadMarkdownApiResult } from './markdown_proce
describe
(
'
markdown processing
'
,
()
=>
{
// Ensure we generate same markdown that was provided to Markdown API.
it
.
each
(
loadMarkdownApiExamples
())(
'
correctly handles %s
'
,
async
(
testName
,
markdown
)
=>
{
const
{
html
}
=
loadMarkdownApiResult
(
testName
);
const
contentEditor
=
createContentEditor
({
renderMarkdown
:
()
=>
html
});
await
contentEditor
.
setSerializedContent
(
markdown
);
it
.
each
(
loadMarkdownApiExamples
())(
'
correctly handles %s (context: %s)
'
,
async
(
name
,
context
,
markdown
)
=>
{
const
testName
=
context
?
`
${
context
}
_
${
name
}
`
:
name
;
const
{
html
,
body
}
=
loadMarkdownApiResult
(
testName
);
const
contentEditor
=
createContentEditor
({
renderMarkdown
:
()
=>
html
||
body
});
await
contentEditor
.
setSerializedContent
(
markdown
);
expect
(
contentEditor
.
getSerializedContent
()).
toBe
(
markdown
);
});
expect
(
contentEditor
.
getSerializedContent
()).
toBe
(
markdown
);
},
);
});
spec/frontend/fixtures/api_markdown.rb
View file @
3a0d395c
...
...
@@ -4,12 +4,32 @@ require 'spec_helper'
RSpec
.
describe
API
::
MergeRequests
,
'(JavaScript fixtures)'
,
type: :request
do
include
ApiHelpers
include
WikiHelpers
include
JavaScriptFixturesHelpers
let_it_be
(
:user
)
{
create
(
:user
)
}
let_it_be
(
:group
)
{
create
(
:group
,
:public
)
}
let_it_be
(
:project
)
{
create
(
:project
,
:public
,
:repository
,
group:
group
)
}
let_it_be
(
:group_wiki
)
{
create
(
:group_wiki
,
user:
user
)
}
let_it_be
(
:project_wiki
)
{
create
(
:project_wiki
,
user:
user
)
}
let
(
:group_wiki_page
)
{
create
(
:wiki_page
,
wiki:
group_wiki
)
}
let
(
:project_wiki_page
)
{
create
(
:wiki_page
,
wiki:
project_wiki
)
}
fixture_subdir
=
'api/markdown'
before
(
:all
)
do
clean_frontend_fixtures
(
fixture_subdir
)
group
.
add_owner
(
user
)
project
.
add_maintainer
(
user
)
end
before
do
stub_group_wikis
(
true
)
sign_in
(
user
)
end
markdown_examples
=
begin
...
...
@@ -19,14 +39,29 @@ RSpec.describe API::MergeRequests, '(JavaScript fixtures)', type: :request do
end
markdown_examples
.
each
do
|
markdown_example
|
context
=
markdown_example
.
fetch
(
:context
,
''
)
name
=
markdown_example
.
fetch
(
:name
)
context
"for
#{
name
}
"
do
context
"for
#{
name
}
#{
!
context
.
empty?
?
" (context:
#{
context
}
)"
:
''
}
"
do
let
(
:markdown
)
{
markdown_example
.
fetch
(
:markdown
)
}
name
=
"
#{
context
}
_
#{
name
}
"
unless
context
.
empty?
it
"
#{
fixture_subdir
}
/
#{
name
}
.json"
do
post
api
(
"/markdown"
),
params:
{
text:
markdown
,
gfm:
true
}
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"
when
'group_wiki'
"/groups/
#{
group
.
full_path
}
/-/wikis/
#{
group_wiki_page
.
slug
}
/preview_markdown"
else
api
"/markdown"
end
post
api_url
,
params:
{
text:
markdown
,
gfm:
true
}
expect
(
response
).
to
be_successful
end
end
...
...
spec/frontend/fixtures/api_markdown.yml
View file @
3a0d395c
...
...
@@ -14,6 +14,18 @@
markdown
:
'
---'
-
name
:
link
markdown
:
'
[GitLab](https://gitlab.com)'
-
name
:
attachment_link
context
:
project_wiki
markdown
:
'
[test-file](test-file.zip)'
-
name
:
attachment_link
context
:
project
markdown
:
'
[test-file](/uploads/aa45a38ec2cfe97433281b10bbff042c/test-file.zip)'
-
name
:
attachment_link
context
:
group_wiki
markdown
:
'
[test-file](test-file.zip)'
-
name
:
attachment_link
context
:
group
markdown
:
'
[test-file](/uploads/aa45a38ec2cfe97433281b10bbff042c/test-file.zip)'
-
name
:
code_block
markdown
:
|-
```javascript
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment