mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
Implement test for search
@appinteractive could you have a look if sanitization of search queries work? I created a test and I see "unterminated string" exceptions. This is not what we want! All user input should be escaped.
This commit is contained in:
parent
5230099e6b
commit
5a995f9f86
@ -3,8 +3,7 @@ type Query {
|
||||
statistics: Statistics!
|
||||
findPosts(filter: String!, limit: Int = 10): [Post]! @cypher(
|
||||
statement: """
|
||||
CALL db.index.fulltext.queryNodes(
|
||||
'full_text_search', $filter+'~')
|
||||
CALL db.index.fulltext.queryNodes('full_text_search', $filter+'~')
|
||||
YIELD node AS node
|
||||
RETURN node
|
||||
ORDER BY node.createdAt DESC
|
||||
|
||||
@ -21,7 +21,7 @@ describe('filter for searchQuery', () => {
|
||||
})
|
||||
await create('post', {
|
||||
title: 'Threepenny Opera',
|
||||
content: 'And the shark, it has teeth, And it wears them in the face.'
|
||||
content: 'And the shark, it has teeth, And it wears them in the face.'
|
||||
})
|
||||
})
|
||||
|
||||
@ -29,6 +29,18 @@ describe('filter for searchQuery', () => {
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('sanitization', () => {
|
||||
it('escapes cypher statement', async () => {
|
||||
await request(host, query(`'');
|
||||
MATCH (n) OPTIONAL MATCH (n)-[r]-() DELETE n,r;
|
||||
CALL db.index.fulltext.queryNodes('full_text_search', ''
|
||||
`))
|
||||
console.log(data)
|
||||
const data = await request(host, query('the'))
|
||||
expect(data).toEqual({findPosts: [{title: 'Hamlet'}, {title: 'Threepenny Opera'}]})
|
||||
})
|
||||
})
|
||||
|
||||
describe('result set', () => {
|
||||
describe('includes posts if search term', () => {
|
||||
it('matches title', async () => {
|
||||
@ -36,8 +48,8 @@ describe('filter for searchQuery', () => {
|
||||
expect(data).toEqual({findPosts: [{title: 'Hamlet'}]})
|
||||
})
|
||||
|
||||
it('matches a part of the title', async () => {
|
||||
const data = await request(host, query('let'))
|
||||
it('matches mistyped title', async () => {
|
||||
const data = await request(host, query('amlet'))
|
||||
expect(data).toEqual({findPosts: [{title: 'Hamlet'}]})
|
||||
})
|
||||
|
||||
|
||||
@ -1,7 +1,16 @@
|
||||
import { GraphQLClient, request } from 'graphql-request'
|
||||
import { getDriver } from '../../bootstrap/neo4j'
|
||||
import { GraphQLClient, request } from "graphql-request";
|
||||
import { getDriver } from "../../bootstrap/neo4j";
|
||||
|
||||
export const seedServerHost = 'http://127.0.0.1:4001'
|
||||
import createBadge from "./badges.js";
|
||||
import createUser from "./users.js";
|
||||
import createOrganization from "./organizations.js";
|
||||
import createPost from "./posts.js";
|
||||
import createComment from "./comments.js";
|
||||
import createCategory from "./categories.js";
|
||||
import createTag from "./tags.js";
|
||||
import createReport from "./reports.js";
|
||||
|
||||
export const seedServerHost = "http://127.0.0.1:4001";
|
||||
|
||||
const authenticatedHeaders = async ({ email, password }, host) => {
|
||||
const mutation = `
|
||||
@ -9,95 +18,85 @@ const authenticatedHeaders = async ({ email, password }, host) => {
|
||||
login(email:"${email}", password:"${password}"){
|
||||
token
|
||||
}
|
||||
}`
|
||||
const response = await request(host, mutation)
|
||||
}`;
|
||||
const response = await request(host, mutation);
|
||||
return {
|
||||
authorization: `Bearer ${response.login.token}`
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
const factories = {
|
||||
'badge': require('./badges.js').default,
|
||||
'user': require('./users.js').default,
|
||||
'organization': require('./organizations.js').default,
|
||||
'post': require('./posts.js').default,
|
||||
'comment': require('./comments.js').default,
|
||||
'category': require('./categories.js').default,
|
||||
'tag': require('./tags.js').default,
|
||||
'report': require('./reports.js').default
|
||||
}
|
||||
|
||||
const relationFactories = {
|
||||
'user': require('./users.js').relate,
|
||||
'organization': require('./organizations.js').relate,
|
||||
'post': require('./posts.js').relate,
|
||||
'comment': require('./comments.js').relate
|
||||
}
|
||||
|
||||
export const create = (model, parameters, options) => {
|
||||
const graphQLClient = new GraphQLClient(seedServerHost, options)
|
||||
const mutation = factories[model](parameters)
|
||||
return graphQLClient.request(mutation)
|
||||
}
|
||||
|
||||
export const relate = (model, type, parameters, options) => {
|
||||
const graphQLClient = new GraphQLClient(seedServerHost, options)
|
||||
const mutation = relationFactories[model](type, parameters)
|
||||
return graphQLClient.request(mutation)
|
||||
}
|
||||
Badge: createBadge,
|
||||
User: createUser,
|
||||
Organization: createOrganization,
|
||||
Post: createPost,
|
||||
Comment: createComment,
|
||||
Category: createCategory,
|
||||
Tag: createTag,
|
||||
Report: createReport
|
||||
};
|
||||
|
||||
export const cleanDatabase = async (options = {}) => {
|
||||
const {
|
||||
driver = getDriver()
|
||||
} = options
|
||||
const session = driver.session()
|
||||
const cypher = 'MATCH (n) DETACH DELETE n'
|
||||
const { driver = getDriver() } = options;
|
||||
const session = driver.session();
|
||||
const cypher = "MATCH (n) DETACH DELETE n";
|
||||
try {
|
||||
return await session.run(cypher)
|
||||
return await session.run(cypher);
|
||||
} catch (error) {
|
||||
throw (error)
|
||||
throw error;
|
||||
} finally {
|
||||
session.close()
|
||||
session.close();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default function Factory (options = {}) {
|
||||
export default function Factory(options = {}) {
|
||||
const {
|
||||
neo4jDriver = getDriver(),
|
||||
seedServerHost = 'http://127.0.0.1:4001'
|
||||
} = options
|
||||
seedServerHost = "http://127.0.0.1:4001"
|
||||
} = options;
|
||||
|
||||
const graphQLClient = new GraphQLClient(seedServerHost)
|
||||
const graphQLClient = new GraphQLClient(seedServerHost);
|
||||
|
||||
const result = {
|
||||
neo4jDriver,
|
||||
seedServerHost,
|
||||
graphQLClient,
|
||||
factories,
|
||||
lastResponse: null,
|
||||
async authenticateAs ({ email, password }) {
|
||||
const headers = await authenticatedHeaders({ email, password }, seedServerHost)
|
||||
this.lastResponse = headers
|
||||
this.graphQLClient = new GraphQLClient(seedServerHost, { headers })
|
||||
return this
|
||||
async authenticateAs({ email, password }) {
|
||||
const headers = await authenticatedHeaders(
|
||||
{ email, password },
|
||||
seedServerHost
|
||||
);
|
||||
this.lastResponse = headers;
|
||||
this.graphQLClient = new GraphQLClient(seedServerHost, { headers });
|
||||
return this;
|
||||
},
|
||||
async create (node, properties) {
|
||||
const mutation = factories[node](properties)
|
||||
this.lastResponse = await this.graphQLClient.request(mutation)
|
||||
return this
|
||||
async create(node, properties) {
|
||||
const mutation = this.factories[node](properties);
|
||||
this.lastResponse = await this.graphQLClient.request(mutation);
|
||||
return this;
|
||||
},
|
||||
async relate (node, relationship, properties) {
|
||||
const mutation = relationFactories[node](relationship, properties)
|
||||
this.lastResponse = await this.graphQLClient.request(mutation)
|
||||
return this
|
||||
async relate(node, relationship, properties) {
|
||||
const { from, to } = properties;
|
||||
const mutation = `
|
||||
mutation {
|
||||
Add${node}${relationship}(
|
||||
from: { id: "${from}" },
|
||||
to: { id: "${to}" }
|
||||
) { from { id } }
|
||||
}
|
||||
`;
|
||||
this.lastResponse = await this.graphQLClient.request(mutation);
|
||||
return this;
|
||||
},
|
||||
async cleanDatabase () {
|
||||
this.lastResponse = await cleanDatabase({ driver: this.neo4jDriver })
|
||||
return this
|
||||
async cleanDatabase() {
|
||||
this.lastResponse = await cleanDatabase({ driver: this.neo4jDriver });
|
||||
return this;
|
||||
}
|
||||
}
|
||||
result.authenticateAs.bind(result)
|
||||
result.create.bind(result)
|
||||
result.relate.bind(result)
|
||||
result.cleanDatabase.bind(result)
|
||||
return result
|
||||
};
|
||||
result.authenticateAs.bind(result);
|
||||
result.create.bind(result);
|
||||
result.relate.bind(result);
|
||||
result.cleanDatabase.bind(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import faker from 'faker'
|
||||
import uuid from 'uuid/v4'
|
||||
import faker from "faker";
|
||||
import uuid from "uuid/v4";
|
||||
|
||||
export default function (params) {
|
||||
export default function(params) {
|
||||
const {
|
||||
id = uuid(),
|
||||
title = faker.lorem.sentence(),
|
||||
@ -11,12 +11,12 @@ export default function (params) {
|
||||
faker.lorem.sentence(),
|
||||
faker.lorem.sentence(),
|
||||
faker.lorem.sentence()
|
||||
].join('. '),
|
||||
].join(". "),
|
||||
image = faker.image.image(),
|
||||
visibility = 'public',
|
||||
visibility = "public",
|
||||
disabled = false,
|
||||
deleted = false
|
||||
} = params
|
||||
} = params;
|
||||
|
||||
return `
|
||||
mutation {
|
||||
@ -30,11 +30,11 @@ export default function (params) {
|
||||
deleted: ${deleted}
|
||||
) { title, content }
|
||||
}
|
||||
`
|
||||
`;
|
||||
}
|
||||
|
||||
export function relate (type, params) {
|
||||
const { from, to } = params
|
||||
export function relate(type, params) {
|
||||
const { from, to } = params;
|
||||
return `
|
||||
mutation {
|
||||
${from}_${type}_${to}: AddPost${type}(
|
||||
@ -42,5 +42,5 @@ export function relate (type, params) {
|
||||
to: { id: "${to}" }
|
||||
) { from { id } }
|
||||
}
|
||||
`
|
||||
`;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user