mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-13 07:46:06 +00:00
Store Hashtags of Post content in database and write a lot of tests
Co-Authored-By: mattwr18 <mattwr18@gmail.com>
This commit is contained in:
parent
f7196e8663
commit
a4cf2d3ee8
@ -21,16 +21,25 @@ const notify = async (postId, idsOfMentionedUsers, context) => {
|
|||||||
|
|
||||||
const updateHashtagsOfPost = async (postId, hashtags, context) => {
|
const updateHashtagsOfPost = async (postId, hashtags, context) => {
|
||||||
const session = context.driver.session()
|
const session = context.driver.session()
|
||||||
const cypher = `
|
// We need two Cypher statements, because the 'MATCH' in the 'cypherDeletePreviousRelations' statement
|
||||||
MATCH (p:Post { id: $postId })-[oldRelations:TAGGED]->(oldTags:Tag)
|
// functions as an 'if'. In case there is no previous relation, the rest of the commands are omitted
|
||||||
DELETE oldRelations
|
// and no new Hashtags and relations will be created.
|
||||||
WITH p
|
const cypherDeletePreviousRelations = `
|
||||||
|
MATCH (p:Post { id: $postId })-[previousRelations:TAGGED]->(t:Tag)
|
||||||
|
DELETE previousRelations
|
||||||
|
RETURN p, t
|
||||||
|
`
|
||||||
|
const cypherCreateNewTagsAndRelations = `
|
||||||
|
MATCH (p:Post { id: $postId})
|
||||||
UNWIND $hashtags AS tagName
|
UNWIND $hashtags AS tagName
|
||||||
MERGE (t:Tag { id: tagName, name: tagName, disabled: false, deleted: false })
|
MERGE (t:Tag { id: tagName, name: tagName, disabled: false, deleted: false })
|
||||||
MERGE (p)-[:TAGGED]->(t)
|
MERGE (p)-[:TAGGED]->(t)
|
||||||
RETURN p, t
|
RETURN p, t
|
||||||
`
|
`
|
||||||
await session.run(cypher, {
|
await session.run(cypherDeletePreviousRelations, {
|
||||||
|
postId,
|
||||||
|
})
|
||||||
|
await session.run(cypherCreateNewTagsAndRelations, {
|
||||||
postId,
|
postId,
|
||||||
hashtags,
|
hashtags,
|
||||||
})
|
})
|
||||||
@ -38,18 +47,14 @@ const updateHashtagsOfPost = async (postId, hashtags, context) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleContentData = async (resolve, root, args, context, resolveInfo) => {
|
const handleContentData = async (resolve, root, args, context, resolveInfo) => {
|
||||||
console.log('args.content: ', args.content)
|
|
||||||
// extract user ids before xss-middleware removes classes via the following "resolve" call
|
// extract user ids before xss-middleware removes classes via the following "resolve" call
|
||||||
const idsOfMentionedUsers = extractMentionedUsers(args.content)
|
const idsOfMentionedUsers = extractMentionedUsers(args.content)
|
||||||
console.log('idsOfMentionedUsers: ', idsOfMentionedUsers)
|
|
||||||
// extract tag (hashtag) ids before xss-middleware removes classes via the following "resolve" call
|
// extract tag (hashtag) ids before xss-middleware removes classes via the following "resolve" call
|
||||||
const hashtags = extractHashtags(args.content)
|
const hashtags = extractHashtags(args.content)
|
||||||
console.log('hashtags: ', hashtags)
|
|
||||||
|
|
||||||
// removes classes from the content
|
// removes classes from the content
|
||||||
const post = await resolve(root, args, context, resolveInfo)
|
const post = await resolve(root, args, context, resolveInfo)
|
||||||
|
|
||||||
console.log('post.id: ', post.id)
|
|
||||||
await notify(post.id, idsOfMentionedUsers, context)
|
await notify(post.id, idsOfMentionedUsers, context)
|
||||||
await updateHashtagsOfPost(post.id, hashtags, context)
|
await updateHashtagsOfPost(post.id, hashtags, context)
|
||||||
|
|
||||||
@ -61,4 +66,4 @@ export default {
|
|||||||
CreatePost: handleContentData,
|
CreatePost: handleContentData,
|
||||||
UpdatePost: handleContentData,
|
UpdatePost: handleContentData,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -1,5 +1,11 @@
|
|||||||
import { GraphQLClient } from 'graphql-request'
|
import {
|
||||||
import { host, login } from '../../jest/helpers'
|
GraphQLClient
|
||||||
|
} from 'graphql-request'
|
||||||
|
import gql from 'graphql-tag'
|
||||||
|
import {
|
||||||
|
host,
|
||||||
|
login
|
||||||
|
} from '../../jest/helpers'
|
||||||
import Factory from '../../seed/factories'
|
import Factory from '../../seed/factories'
|
||||||
|
|
||||||
const factory = Factory()
|
const factory = Factory()
|
||||||
@ -20,22 +26,29 @@ afterEach(async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('currentUser { notifications }', () => {
|
describe('currentUser { notifications }', () => {
|
||||||
const query = `query($read: Boolean) {
|
const query = gql `
|
||||||
currentUser {
|
query($read: Boolean) {
|
||||||
notifications(read: $read, orderBy: createdAt_desc) {
|
currentUser {
|
||||||
read
|
notifications(read: $read, orderBy: createdAt_desc) {
|
||||||
post {
|
read
|
||||||
content
|
post {
|
||||||
}
|
content
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}`
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
describe('authenticated', () => {
|
describe('authenticated', () => {
|
||||||
let headers
|
let headers
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
headers = await login({ email: 'test@example.org', password: '1234' })
|
headers = await login({
|
||||||
client = new GraphQLClient(host, { headers })
|
email: 'test@example.org',
|
||||||
|
password: '1234',
|
||||||
|
})
|
||||||
|
client = new GraphQLClient(host, {
|
||||||
|
headers,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('given another user', () => {
|
describe('given another user', () => {
|
||||||
@ -60,17 +73,24 @@ describe('currentUser { notifications }', () => {
|
|||||||
'Hey <a class="mention" href="/profile/you/al-capone">@al-capone</a> how do you do?'
|
'Hey <a class="mention" href="/profile/you/al-capone">@al-capone</a> how do you do?'
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const createPostMutation = `
|
const createPostMutation = gql `
|
||||||
mutation($title: String!, $content: String!) {
|
mutation($title: String!, $content: String!) {
|
||||||
CreatePost(title: $title, content: $content) {
|
CreatePost(title: $title, content: $content) {
|
||||||
id
|
id
|
||||||
title
|
title
|
||||||
content
|
content
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
`
|
`
|
||||||
authorClient = new GraphQLClient(host, { headers: authorHeaders })
|
authorClient = new GraphQLClient(host, {
|
||||||
const { CreatePost } = await authorClient.request(createPostMutation, { title, content })
|
headers: authorHeaders,
|
||||||
|
})
|
||||||
|
const {
|
||||||
|
CreatePost
|
||||||
|
} = await authorClient.request(createPostMutation, {
|
||||||
|
title,
|
||||||
|
content,
|
||||||
|
})
|
||||||
post = CreatePost
|
post = CreatePost
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -79,10 +99,19 @@ describe('currentUser { notifications }', () => {
|
|||||||
'Hey <a href="/profile/you/al-capone" target="_blank">@al-capone</a> how do you do?'
|
'Hey <a href="/profile/you/al-capone" target="_blank">@al-capone</a> how do you do?'
|
||||||
const expected = {
|
const expected = {
|
||||||
currentUser: {
|
currentUser: {
|
||||||
notifications: [{ read: false, post: { content: expectedContent } }],
|
notifications: [{
|
||||||
|
read: false,
|
||||||
|
post: {
|
||||||
|
content: expectedContent,
|
||||||
|
},
|
||||||
|
}, ],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
await expect(client.request(query, { read: false })).resolves.toEqual(expected)
|
await expect(
|
||||||
|
client.request(query, {
|
||||||
|
read: false,
|
||||||
|
}),
|
||||||
|
).resolves.toEqual(expected)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('who mentions me again', () => {
|
describe('who mentions me again', () => {
|
||||||
@ -93,16 +122,21 @@ describe('currentUser { notifications }', () => {
|
|||||||
// during development and thought: A feature not a bug! This way we
|
// during development and thought: A feature not a bug! This way we
|
||||||
// can encode a re-mentioning of users when you edit your post or
|
// can encode a re-mentioning of users when you edit your post or
|
||||||
// comment.
|
// comment.
|
||||||
const createPostMutation = `
|
const createPostMutation = gql `
|
||||||
mutation($id: ID!, $content: String!) {
|
mutation($id: ID!, $content: String!) {
|
||||||
UpdatePost(id: $id, content: $content) {
|
UpdatePost(id: $id, content: $content) {
|
||||||
title
|
title
|
||||||
content
|
content
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
`
|
`
|
||||||
authorClient = new GraphQLClient(host, { headers: authorHeaders })
|
authorClient = new GraphQLClient(host, {
|
||||||
await authorClient.request(createPostMutation, { id: post.id, content: updatedContent })
|
headers: authorHeaders,
|
||||||
|
})
|
||||||
|
await authorClient.request(createPostMutation, {
|
||||||
|
id: post.id,
|
||||||
|
content: updatedContent,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('creates exactly one more notification', async () => {
|
it('creates exactly one more notification', async () => {
|
||||||
@ -110,16 +144,135 @@ describe('currentUser { notifications }', () => {
|
|||||||
'Hey <a href="/profile/you/al-capone" target="_blank">@al-capone</a> how do you do? One more mention to <a href="/profile/you" target="_blank">@al-capone</a>'
|
'Hey <a href="/profile/you/al-capone" target="_blank">@al-capone</a> how do you do? One more mention to <a href="/profile/you" target="_blank">@al-capone</a>'
|
||||||
const expected = {
|
const expected = {
|
||||||
currentUser: {
|
currentUser: {
|
||||||
notifications: [
|
notifications: [{
|
||||||
{ read: false, post: { content: expectedContent } },
|
read: false,
|
||||||
{ read: false, post: { content: expectedContent } },
|
post: {
|
||||||
|
content: expectedContent,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
read: false,
|
||||||
|
post: {
|
||||||
|
content: expectedContent,
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
await expect(client.request(query, { read: false })).resolves.toEqual(expected)
|
await expect(
|
||||||
|
client.request(query, {
|
||||||
|
read: false,
|
||||||
|
}),
|
||||||
|
).resolves.toEqual(expected)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('Hashtags', () => {
|
||||||
|
const postId = 'p135'
|
||||||
|
const postTitle = 'Two Hashtags'
|
||||||
|
const postContent =
|
||||||
|
'<p>Hey Dude, <a class="hashtag" href="/search/hashtag/Democracy">#Democracy</a> should work equal for everybody!? That seems to be the only way to have equal <a class="hashtag" href="/search/hashtag/Liberty">#Liberty</a> for everyone.</p>'
|
||||||
|
const postWithHastagsQuery = gql `
|
||||||
|
query($id: ID) {
|
||||||
|
Post(id: $id) {
|
||||||
|
tags {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
const postWithHastagsVariables = {
|
||||||
|
id: postId,
|
||||||
|
}
|
||||||
|
const createPostMutation = gql `
|
||||||
|
mutation($postId: ID, $postTitle: String!, $postContent: String!) {
|
||||||
|
CreatePost(id: $postId, title: $postTitle, content: $postContent) {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
describe('authenticated', () => {
|
||||||
|
let headers
|
||||||
|
beforeEach(async () => {
|
||||||
|
headers = await login({
|
||||||
|
email: 'test@example.org',
|
||||||
|
password: '1234',
|
||||||
|
})
|
||||||
|
client = new GraphQLClient(host, {
|
||||||
|
headers,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('create a Post with Hashtags', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await client.request(createPostMutation, {
|
||||||
|
postId,
|
||||||
|
postTitle,
|
||||||
|
postContent,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('both Hashtags are created', async () => {
|
||||||
|
const expected = [{
|
||||||
|
name: 'Democracy',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Liberty',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
await expect(
|
||||||
|
client.request(postWithHastagsQuery, postWithHastagsVariables),
|
||||||
|
).resolves.toEqual({
|
||||||
|
Post: [{
|
||||||
|
tags: expect.arrayContaining(expected),
|
||||||
|
}, ],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('afterwards update the Post by removing a Hashtag, leaving a Hashtag and add a Hashtag', () => {
|
||||||
|
// The already existing Hashtag has no class at this point.
|
||||||
|
const updatedPostContent =
|
||||||
|
'<p>Hey Dude, <a class="hashtag" href="/search/hashtag/Elections">#Elections</a> should work equal for everybody!? That seems to be the only way to have equal <a href="/search/hashtag/Liberty">#Liberty</a> for everyone.</p>'
|
||||||
|
const updatePostMutation = gql `
|
||||||
|
mutation($postId: ID!, $postTitle: String, $updatedPostContent: String) {
|
||||||
|
UpdatePost(id: $postId, title: $postTitle, content: $updatedPostContent) {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
it('only one previous Hashtag and the new Hashtag exists', async () => {
|
||||||
|
await client.request(updatePostMutation, {
|
||||||
|
postId,
|
||||||
|
postTitle,
|
||||||
|
updatedPostContent,
|
||||||
|
})
|
||||||
|
|
||||||
|
const expected = [{
|
||||||
|
name: 'Elections',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Liberty',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
await expect(
|
||||||
|
client.request(postWithHastagsQuery, postWithHastagsVariables),
|
||||||
|
).resolves.toEqual({
|
||||||
|
Post: [{
|
||||||
|
tags: expect.arrayContaining(expected),
|
||||||
|
}, ],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -1,21 +1,22 @@
|
|||||||
import cheerio from 'cheerio'
|
import cheerio from 'cheerio'
|
||||||
const ID_REGEX = /\/search\/hashtag\/([\w\-.!~*'"(),]+)/g
|
const ID_REGEX = /\/search\/hashtag\/([\w\-.!~*'"(),]+)/g
|
||||||
|
|
||||||
export default function(content) {
|
export default function (content) {
|
||||||
if (!content) return []
|
if (!content) return []
|
||||||
const $ = cheerio.load(content)
|
const $ = cheerio.load(content)
|
||||||
const urls = $('.hashtag')
|
// We can not search for class '.hashtag', because the classes are removed at the 'xss' middleware.
|
||||||
|
// But we have to know, which Hashtags are removed from the content es well, so we search for the 'a' html-tag.
|
||||||
|
const urls = $('a')
|
||||||
.map((_, el) => {
|
.map((_, el) => {
|
||||||
return $(el).attr('href')
|
return $(el).attr('href')
|
||||||
})
|
})
|
||||||
.get()
|
.get()
|
||||||
const hashtags = []
|
const hashtags = []
|
||||||
urls.forEach(url => {
|
urls.forEach(url => {
|
||||||
console.log('url: ', url)
|
|
||||||
let match
|
let match
|
||||||
while ((match = ID_REGEX.exec(url)) != null) {
|
while ((match = ID_REGEX.exec(url)) != null) {
|
||||||
hashtags.push(match[1])
|
hashtags.push(match[1])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return hashtags
|
return hashtags
|
||||||
}
|
}
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
import extractHashtags from './extractHashtags'
|
||||||
|
|
||||||
|
describe('extractHashtags', () => {
|
||||||
|
describe('content undefined', () => {
|
||||||
|
it('returns empty array', () => {
|
||||||
|
expect(extractHashtags()).toEqual([])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('searches through links', () => {
|
||||||
|
it('finds links with and without ".hashtag" class and extracts Hashtag names', () => {
|
||||||
|
const content =
|
||||||
|
'<p><a class="hashtag" href="/search/hashtag/Elections">#Elections</a><a href="/search/hashtag/Democracy">#Democracy</a></p>'
|
||||||
|
expect(extractHashtags(content)).toEqual(['Elections', 'Democracy'])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('ignores mentions', () => {
|
||||||
|
const content =
|
||||||
|
'<p>Something inspirational about <a href="/profile/u2" target="_blank">@bob-der-baumeister</a> and <a href="/profile/u3/jenny-rostock" class="mention" target="_blank">@jenny-rostock</a>.</p>'
|
||||||
|
expect(extractHashtags(content)).toEqual([])
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('handles links', () => {
|
||||||
|
it('with domains', () => {
|
||||||
|
const content =
|
||||||
|
'<p><a class="hashtag" href="http://localhost:3000/search/hashtag/Elections">#Elections</a><a href="http://localhost:3000/search/hashtag/Democracy">#Democracy</a></p>'
|
||||||
|
expect(extractHashtags(content)).toEqual(['Elections', 'Democracy'])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('special characters', () => {
|
||||||
|
const content =
|
||||||
|
'<p>Something inspirational about <a href="/search/hashtag/u!*(),2" class="hashtag" target="_blank">#u!*(),2</a> and <a href="/search/hashtag/u.~-3" target="_blank">#u.~-3</a>.</p>'
|
||||||
|
expect(extractHashtags(content)).toEqual(['u!*(),2', 'u.~-3'])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('does not crash if', () => {
|
||||||
|
it('`href` contains no Hashtag name', () => {
|
||||||
|
const content =
|
||||||
|
'<p>Something inspirational about <a href="/search/hashtag/" target="_blank">#Democracy</a> and <a href="/search/hashtag" target="_blank">#liberty</a>.</p>'
|
||||||
|
expect(extractHashtags(content)).toEqual([])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('`href` is empty or invalid', () => {
|
||||||
|
const content =
|
||||||
|
'<p>Something inspirational about <a href="" class="hashtag" target="_blank">@bob-der-baumeister</a> and <a href="not-a-url" target="_blank">@jenny-rostock</a>.</p>'
|
||||||
|
expect(extractHashtags(content)).toEqual([])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import cheerio from 'cheerio'
|
import cheerio from 'cheerio'
|
||||||
const ID_REGEX = /\/profile\/([\w\-.!~*'"(),]+)/g
|
const ID_REGEX = /\/profile\/([\w\-.!~*'"(),]+)/g
|
||||||
|
|
||||||
export default function(content) {
|
export default function (content) {
|
||||||
if (!content) return []
|
if (!content) return []
|
||||||
const $ = cheerio.load(content)
|
const $ = cheerio.load(content)
|
||||||
const urls = $('.mention')
|
const urls = $('.mention')
|
||||||
@ -11,11 +11,10 @@ export default function(content) {
|
|||||||
.get()
|
.get()
|
||||||
const ids = []
|
const ids = []
|
||||||
urls.forEach(url => {
|
urls.forEach(url => {
|
||||||
console.log('url: ', url)
|
|
||||||
let match
|
let match
|
||||||
while ((match = ID_REGEX.exec(url)) != null) {
|
while ((match = ID_REGEX.exec(url)) != null) {
|
||||||
ids.push(match[1])
|
ids.push(match[1])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return ids
|
return ids
|
||||||
}
|
}
|
||||||
@ -1,9 +1,9 @@
|
|||||||
import extractIds from './extractMentionedUsers'
|
import extractMentionedUsers from './extractMentionedUsers'
|
||||||
|
|
||||||
describe('extractIds', () => {
|
describe('extractMentionedUsers', () => {
|
||||||
describe('content undefined', () => {
|
describe('content undefined', () => {
|
||||||
it('returns empty array', () => {
|
it('returns empty array', () => {
|
||||||
expect(extractIds()).toEqual([])
|
expect(extractMentionedUsers()).toEqual([])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -11,33 +11,33 @@ describe('extractIds', () => {
|
|||||||
it('ignores links without .mention class', () => {
|
it('ignores links without .mention class', () => {
|
||||||
const content =
|
const content =
|
||||||
'<p>Something inspirational about <a href="/profile/u2" target="_blank">@bob-der-baumeister</a> and <a href="/profile/u3" target="_blank">@jenny-rostock</a>.</p>'
|
'<p>Something inspirational about <a href="/profile/u2" target="_blank">@bob-der-baumeister</a> and <a href="/profile/u3" target="_blank">@jenny-rostock</a>.</p>'
|
||||||
expect(extractIds(content)).toEqual([])
|
expect(extractMentionedUsers(content)).toEqual([])
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('given a link with .mention class', () => {
|
describe('given a link with .mention class', () => {
|
||||||
it('extracts ids', () => {
|
it('extracts ids', () => {
|
||||||
const content =
|
const content =
|
||||||
'<p>Something inspirational about <a href="/profile/u2" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="/profile/u3/jenny-rostock" class="mention" target="_blank">@jenny-rostock</a>.</p>'
|
'<p>Something inspirational about <a href="/profile/u2" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="/profile/u3/jenny-rostock" class="mention" target="_blank">@jenny-rostock</a>.</p>'
|
||||||
expect(extractIds(content)).toEqual(['u2', 'u3'])
|
expect(extractMentionedUsers(content)).toEqual(['u2', 'u3'])
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('handles links', () => {
|
describe('handles links', () => {
|
||||||
it('with slug and id', () => {
|
it('with slug and id', () => {
|
||||||
const content =
|
const content =
|
||||||
'<p>Something inspirational about <a href="/profile/u2/bob-der-baumeister" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="/profile/u3/jenny-rostock/" class="mention" target="_blank">@jenny-rostock</a>.</p>'
|
'<p>Something inspirational about <a href="/profile/u2/bob-der-baumeister" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="/profile/u3/jenny-rostock/" class="mention" target="_blank">@jenny-rostock</a>.</p>'
|
||||||
expect(extractIds(content)).toEqual(['u2', 'u3'])
|
expect(extractMentionedUsers(content)).toEqual(['u2', 'u3'])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('with domains', () => {
|
it('with domains', () => {
|
||||||
const content =
|
const content =
|
||||||
'<p>Something inspirational about <a href="http://localhost:3000/profile/u2/bob-der-baumeister" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="http://localhost:3000//profile/u3/jenny-rostock/" class="mention" target="_blank">@jenny-rostock</a>.</p>'
|
'<p>Something inspirational about <a href="http://localhost:3000/profile/u2/bob-der-baumeister" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="http://localhost:3000//profile/u3/jenny-rostock/" class="mention" target="_blank">@jenny-rostock</a>.</p>'
|
||||||
expect(extractIds(content)).toEqual(['u2', 'u3'])
|
expect(extractMentionedUsers(content)).toEqual(['u2', 'u3'])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('special characters', () => {
|
it('special characters', () => {
|
||||||
const content =
|
const content =
|
||||||
'<p>Something inspirational about <a href="http://localhost:3000/profile/u!*(),2/bob-der-baumeister" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="http://localhost:3000//profile/u.~-3/jenny-rostock/" class="mention" target="_blank">@jenny-rostock</a>.</p>'
|
'<p>Something inspirational about <a href="http://localhost:3000/profile/u!*(),2/bob-der-baumeister" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="http://localhost:3000//profile/u.~-3/jenny-rostock/" class="mention" target="_blank">@jenny-rostock</a>.</p>'
|
||||||
expect(extractIds(content)).toEqual(['u!*(),2', 'u.~-3'])
|
expect(extractMentionedUsers(content)).toEqual(['u!*(),2', 'u.~-3'])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -45,15 +45,15 @@ describe('extractIds', () => {
|
|||||||
it('`href` contains no user id', () => {
|
it('`href` contains no user id', () => {
|
||||||
const content =
|
const content =
|
||||||
'<p>Something inspirational about <a href="/profile" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="/profile/" class="mention" target="_blank">@jenny-rostock</a>.</p>'
|
'<p>Something inspirational about <a href="/profile" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="/profile/" class="mention" target="_blank">@jenny-rostock</a>.</p>'
|
||||||
expect(extractIds(content)).toEqual([])
|
expect(extractMentionedUsers(content)).toEqual([])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('`href` is empty or invalid', () => {
|
it('`href` is empty or invalid', () => {
|
||||||
const content =
|
const content =
|
||||||
'<p>Something inspirational about <a href="" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="not-a-url" class="mention" target="_blank">@jenny-rostock</a>.</p>'
|
'<p>Something inspirational about <a href="" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="not-a-url" class="mention" target="_blank">@jenny-rostock</a>.</p>'
|
||||||
expect(extractIds(content)).toEqual([])
|
expect(extractMentionedUsers(content)).toEqual([])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -28,16 +28,16 @@
|
|||||||
<ds-space />
|
<ds-space />
|
||||||
<div slot="footer" style="text-align: right">
|
<div slot="footer" style="text-align: right">
|
||||||
<ds-button
|
<ds-button
|
||||||
|
class="cancel-button"
|
||||||
:disabled="loading || disabled"
|
:disabled="loading || disabled"
|
||||||
ghost
|
ghost
|
||||||
class="cancel-button"
|
@click.prevent="$router.back()"
|
||||||
@click="$router.back()"
|
|
||||||
>
|
>
|
||||||
{{ $t('actions.cancel') }}
|
{{ $t('actions.cancel') }}
|
||||||
</ds-button>
|
</ds-button>
|
||||||
<ds-button
|
<ds-button
|
||||||
icon="check"
|
|
||||||
type="submit"
|
type="submit"
|
||||||
|
icon="check"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:disabled="disabled || errors"
|
:disabled="disabled || errors"
|
||||||
primary
|
primary
|
||||||
@ -52,7 +52,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import gql from 'graphql-tag'
|
import gql from 'graphql-tag'
|
||||||
import HcEditor from '~/components/Editor'
|
import HcEditor from '~/components/Editor/Editor'
|
||||||
import orderBy from 'lodash/orderBy'
|
import orderBy from 'lodash/orderBy'
|
||||||
import locales from '~/locales'
|
import locales from '~/locales'
|
||||||
import PostMutations from '~/graphql/PostMutations.js'
|
import PostMutations from '~/graphql/PostMutations.js'
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { mount, createLocalVue } from '@vue/test-utils'
|
import { mount, createLocalVue } from '@vue/test-utils'
|
||||||
import Editor from './'
|
import Editor from './Editor'
|
||||||
import Vuex from 'vuex'
|
import Vuex from 'vuex'
|
||||||
|
|
||||||
import Styleguide from '@human-connection/styleguide'
|
import Styleguide from '@human-connection/styleguide'
|
||||||
@ -36,7 +36,9 @@ describe('Editor.vue', () => {
|
|||||||
propsData,
|
propsData,
|
||||||
localVue,
|
localVue,
|
||||||
sync: false,
|
sync: false,
|
||||||
stubs: { transition: false },
|
stubs: {
|
||||||
|
transition: false,
|
||||||
|
},
|
||||||
store,
|
store,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import gql from 'graphql-tag'
|
import gql from 'graphql-tag'
|
||||||
import HcEditor from '~/components/Editor'
|
import HcEditor from '~/components/Editor/Editor'
|
||||||
import PostCommentsQuery from '~/graphql/PostCommentsQuery.js'
|
import PostCommentsQuery from '~/graphql/PostCommentsQuery.js'
|
||||||
import CommentMutations from '~/graphql/CommentMutations.js'
|
import CommentMutations from '~/graphql/CommentMutations.js'
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user