diff --git a/backend/package.json b/backend/package.json index 22abc010f..98672be83 100644 --- a/backend/package.json +++ b/backend/package.json @@ -61,7 +61,7 @@ "graphql-middleware": "~4.0.2", "graphql-middleware-sentry": "^3.2.1", "graphql-redis-subscriptions": "^2.1.2", - "graphql-shield": "~7.0.10", + "graphql-shield": "~7.0.11", "graphql-tag": "~2.10.3", "helmet": "~3.21.2", "ioredis": "^4.14.1", @@ -130,6 +130,7 @@ "jest": "~25.1.0", "nodemon": "~2.0.2", "prettier": "~1.19.1", + "rosie": "^2.0.1", "supertest": "~4.0.2" } } diff --git a/backend/src/activitypub/routes/webfinger.spec.js b/backend/src/activitypub/routes/webfinger.spec.js index 06ca4577d..3cd9613e7 100644 --- a/backend/src/activitypub/routes/webfinger.spec.js +++ b/backend/src/activitypub/routes/webfinger.spec.js @@ -1,10 +1,9 @@ import { handler } from './webfinger' -import Factory from '../../factories' +import Factory, { cleanDatabase } from '../../db/factories' import { getDriver } from '../../db/neo4j' let resource, res, json, status, contentType -const factory = Factory() const driver = getDriver() const request = () => { @@ -28,7 +27,7 @@ const request = () => { } afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('webfinger', () => { @@ -90,7 +89,7 @@ describe('webfinger', () => { describe('given a user for acct', () => { beforeEach(async () => { - await factory.create('User', { slug: 'some-user' }) + await Factory.build('user', { slug: 'some-user' }) }) it('returns user object', async () => { diff --git a/backend/src/config/index.js b/backend/src/config/index.js index 8bbff8817..398bc6ff2 100644 --- a/backend/src/config/index.js +++ b/backend/src/config/index.js @@ -4,6 +4,9 @@ if (require.resolve) { dotenv.config({ path: require.resolve('../../.env') }) } +// eslint-disable-next-line no-undef +const env = typeof Cypress !== 'undefined' ? Cypress.env() : process.env + const { MAPBOX_TOKEN, JWT_SECRET, @@ -23,7 +26,7 @@ const { REDIS_DOMAIN, REDIS_PORT, REDIS_PASSWORD, -} = process.env +} = env export const requiredConfigs = { MAPBOX_TOKEN, diff --git a/backend/src/db/clean.js b/backend/src/db/clean.js index cbb1412e2..e658317e2 100644 --- a/backend/src/db/clean.js +++ b/backend/src/db/clean.js @@ -1,4 +1,4 @@ -import { cleanDatabase } from '../factories' +import { cleanDatabase } from '../db/factories' if (process.env.NODE_ENV === 'production') { throw new Error(`You cannot clean the database in production environment!`) diff --git a/backend/src/db/factories.js b/backend/src/db/factories.js new file mode 100644 index 000000000..7a8979b3c --- /dev/null +++ b/backend/src/db/factories.js @@ -0,0 +1,226 @@ +import uuid from 'uuid/v4' +import faker from 'faker' +import slugify from 'slug' +import { hashSync } from 'bcryptjs' +import { Factory } from 'rosie' +import { getDriver, getNeode } from './neo4j' + +const neode = getNeode() + +export const cleanDatabase = async (options = {}) => { + const { driver = getDriver() } = options + const session = driver.session() + try { + await session.writeTransaction(transaction => { + return transaction.run( + ` + MATCH (everything) + DETACH DELETE everything + `, + ) + }) + } finally { + session.close() + } +} + +Factory.define('category') + .attr('id', uuid) + .attr('icon', 'globe') + .attr('name', 'global-peace-nonviolence') + .after((buildObject, options) => { + return neode.create('Category', buildObject) + }) + +Factory.define('badge') + .attr('type', 'crowdfunding') + .attr('status', 'permanent') + .after((buildObject, options) => { + return neode.create('Badge', buildObject) + }) + +Factory.define('userWithoutEmailAddress') + .option('password', '1234') + .attrs({ + id: uuid, + name: faker.name.findName, + password: '1234', + role: 'user', + avatar: faker.internet.avatar, + about: faker.lorem.paragraph, + termsAndConditionsAgreedVersion: '0.0.1', + termsAndConditionsAgreedAt: '2019-08-01T10:47:19.212Z', + allowEmbedIframes: false, + showShoutsPublicly: false, + locale: 'en', + }) + .attr('slug', ['slug', 'name'], (slug, name) => { + return slug || slugify(name, { lower: true }) + }) + .attr('encryptedPassword', ['password'], password => { + return hashSync(password, 10) + }) + .after(async (buildObject, options) => { + return neode.create('User', buildObject) + }) + +Factory.define('user') + .extend('userWithoutEmailAddress') + .option('email', faker.internet.exampleEmail) + .after(async (buildObject, options) => { + const [user, email] = await Promise.all([ + buildObject, + neode.create('EmailAddress', { email: options.email }), + ]) + await Promise.all([user.relateTo(email, 'primaryEmail'), email.relateTo(user, 'belongsTo')]) + return user + }) + +Factory.define('post') + .option('categoryIds', []) + .option('categories', ['categoryIds'], categoryIds => { + if (categoryIds.length) return Promise.all(categoryIds.map(id => neode.find('Category', id))) + // there must be at least one category + return Promise.all([Factory.build('category')]) + }) + .option('tagIds', []) + .option('tags', ['tagIds'], tagIds => { + return Promise.all(tagIds.map(id => neode.find('Tag', id))) + }) + .option('authorId', null) + .option('author', ['authorId'], authorId => { + if (authorId) return neode.find('User', authorId) + return Factory.build('user') + }) + .option('pinnedBy', null) + .attrs({ + id: uuid, + title: faker.lorem.sentence, + content: faker.lorem.paragraphs, + image: faker.image.unsplash.imageUrl, + visibility: 'public', + deleted: false, + imageBlurred: false, + imageAspectRatio: 1.333, + }) + .attr('pinned', ['pinned'], pinned => { + // Convert false to null + return pinned || null + }) + .attr('contentExcerpt', ['contentExcerpt', 'content'], (contentExcerpt, content) => { + return contentExcerpt || content + }) + .attr('slug', ['slug', 'title'], (slug, title) => { + return slug || slugify(title, { lower: true }) + }) + .after(async (buildObject, options) => { + const [post, author, categories, tags] = await Promise.all([ + neode.create('Post', buildObject), + options.author, + options.categories, + options.tags, + ]) + await Promise.all([ + post.relateTo(author, 'author'), + Promise.all(categories.map(c => c.relateTo(post, 'post'))), + Promise.all(tags.map(t => t.relateTo(post, 'post'))), + ]) + if (buildObject.pinned) { + const pinnedBy = await (options.pinnedBy || Factory.build('user', { role: 'admin' })) + await pinnedBy.relateTo(post, 'pinned') + } + return post + }) + +Factory.define('comment') + .option('postId', null) + .option('post', ['postId'], postId => { + if (postId) return neode.find('Post', postId) + return Factory.build('post') + }) + .option('authorId', null) + .option('author', ['authorId'], authorId => { + if (authorId) return neode.find('User', authorId) + return Factory.build('user') + }) + .attrs({ + id: uuid, + content: faker.lorem.sentence, + }) + .attr('contentExcerpt', ['contentExcerpt', 'content'], (contentExcerpt, content) => { + return contentExcerpt || content + }) + .after(async (buildObject, options) => { + const [comment, author, post] = await Promise.all([ + neode.create('Comment', buildObject), + options.author, + options.post, + ]) + await Promise.all([comment.relateTo(author, 'author'), comment.relateTo(post, 'post')]) + return comment + }) + +Factory.define('donations') + .attr('id', uuid) + .attr('goal', 15000) + .attr('progress', 0) + .after((buildObject, options) => { + return neode.create('Donations', buildObject) + }) + +const emailDefaults = { + email: faker.internet.email, + verifiedAt: () => new Date().toISOString(), +} + +Factory.define('emailAddress') + .attr(emailDefaults) + .after((buildObject, options) => { + return neode.create('EmailAddress', buildObject) + }) + +Factory.define('unverifiedEmailAddress') + .attr(emailDefaults) + .after((buildObject, options) => { + return neode.create('UnverifiedEmailAddress', buildObject) + }) + +Factory.define('location') + .attrs({ + name: 'Germany', + namePT: 'Alemanha', + nameDE: 'Deutschland', + nameES: 'Alemania', + nameNL: 'Duitsland', + namePL: 'Niemcy', + nameFR: 'Allemagne', + nameIT: 'Germania', + nameEN: 'Germany', + id: 'country.10743216036480410', + type: 'country', + }) + .after((buildObject, options) => { + return neode.create('Location', buildObject) + }) + +Factory.define('report').after((buildObject, options) => { + return neode.create('Report', buildObject) +}) + +Factory.define('tag') + .attrs({ + name: '#human-connection', + }) + .after((buildObject, options) => { + return neode.create('Tag', buildObject) + }) + +Factory.define('socialMedia') + .attrs({ + url: 'https://mastodon.social/@Gargron', + }) + .after((buildObject, options) => { + return neode.create('SocialMedia', buildObject) + }) + +export default Factory diff --git a/backend/src/db/seed.js b/backend/src/db/seed.js index ba7ace90b..f966f8b07 100644 --- a/backend/src/db/seed.js +++ b/backend/src/db/seed.js @@ -2,7 +2,7 @@ import faker from 'faker' import sample from 'lodash/sample' import { createTestClient } from 'apollo-server-testing' import createServer from '../server' -import Factory from '../factories' +import Factory from '../db/factories' import { getNeode, getDriver } from '../db/neo4j' import { gql } from '../helpers/jest' @@ -12,7 +12,6 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] ;(async function() { let authenticatedUser = null const driver = getDriver() - const factory = Factory() const neode = getNeode() try { @@ -28,7 +27,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] const { mutate } = createTestClient(server) const [Hamburg, Berlin, Germany, Paris, France] = await Promise.all([ - factory.create('Location', { + Factory.build('location', { id: 'region.5127278006398860', name: 'Hamburg', type: 'region', @@ -44,7 +43,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] namePL: 'Hamburg', nameRU: 'Гамбург', }), - factory.create('Location', { + Factory.build('location', { id: 'region.14880313158564380', type: 'region', name: 'Berlin', @@ -60,7 +59,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] namePL: 'Berlin', nameRU: 'Берлин', }), - factory.create('Location', { + Factory.build('location', { id: 'country.10743216036480410', name: 'Germany', type: 'country', @@ -74,7 +73,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] nameEN: 'Germany', nameRU: 'Германия', }), - factory.create('Location', { + Factory.build('location', { id: 'region.9397217726497330', name: 'Paris', type: 'region', @@ -90,7 +89,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] namePL: 'Paryż', nameRU: 'Париж', }), - factory.create('Location', { + Factory.build('location', { id: 'country.9759535382641660', name: 'France', type: 'country', @@ -112,27 +111,27 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] ]) const [racoon, rabbit, wolf, bear, turtle, rhino] = await Promise.all([ - factory.create('Badge', { + Factory.build('badge', { id: 'indiegogo_en_racoon', icon: '/img/badges/indiegogo_en_racoon.svg', }), - factory.create('Badge', { + Factory.build('badge', { id: 'indiegogo_en_rabbit', icon: '/img/badges/indiegogo_en_rabbit.svg', }), - factory.create('Badge', { + Factory.build('badge', { id: 'indiegogo_en_wolf', icon: '/img/badges/indiegogo_en_wolf.svg', }), - factory.create('Badge', { + Factory.build('badge', { id: 'indiegogo_en_bear', icon: '/img/badges/indiegogo_en_bear.svg', }), - factory.create('Badge', { + Factory.build('badge', { id: 'indiegogo_en_turtle', icon: '/img/badges/indiegogo_en_turtle.svg', }), - factory.create('Badge', { + Factory.build('badge', { id: 'indiegogo_en_rhino', icon: '/img/badges/indiegogo_en_rhino.svg', }), @@ -147,55 +146,90 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] louie, dagobert, ] = await Promise.all([ - factory.create('User', { - id: 'u1', - name: 'Peter Lustig', - slug: 'peter-lustig', - role: 'admin', - email: 'admin@example.org', - }), - factory.create('User', { - id: 'u2', - name: 'Bob der Baumeister', - slug: 'bob-der-baumeister', - role: 'moderator', - email: 'moderator@example.org', - }), - factory.create('User', { - id: 'u3', - name: 'Jenny Rostock', - slug: 'jenny-rostock', - role: 'user', - email: 'user@example.org', - }), - factory.create('User', { - id: 'u4', - name: 'Huey', - slug: 'huey', - role: 'user', - email: 'huey@example.org', - }), - factory.create('User', { - id: 'u5', - name: 'Dewey', - slug: 'dewey', - role: 'user', - email: 'dewey@example.org', - }), - factory.create('User', { - id: 'u6', - name: 'Louie', - slug: 'louie', - role: 'user', - email: 'louie@example.org', - }), - factory.create('User', { - id: 'u7', - name: 'Dagobert', - slug: 'dagobert', - role: 'user', - email: 'dagobert@example.org', - }), + Factory.build( + 'user', + { + id: 'u1', + name: 'Peter Lustig', + slug: 'peter-lustig', + role: 'admin', + }, + { + email: 'admin@example.org', + }, + ), + Factory.build( + 'user', + { + id: 'u2', + name: 'Bob der Baumeister', + slug: 'bob-der-baumeister', + role: 'moderator', + }, + { + email: 'moderator@example.org', + }, + ), + Factory.build( + 'user', + { + id: 'u3', + name: 'Jenny Rostock', + slug: 'jenny-rostock', + role: 'user', + }, + { + email: 'user@example.org', + }, + ), + Factory.build( + 'user', + { + id: 'u4', + name: 'Huey', + slug: 'huey', + role: 'user', + }, + { + email: 'huey@example.org', + }, + ), + Factory.build( + 'user', + { + id: 'u5', + name: 'Dewey', + slug: 'dewey', + role: 'user', + }, + { + email: 'dewey@example.org', + }, + ), + Factory.build( + 'user', + { + id: 'u6', + name: 'Louie', + slug: 'louie', + role: 'user', + }, + { + email: 'louie@example.org', + }, + ), + Factory.build( + 'user', + { + id: 'u7', + name: 'Dagobert', + slug: 'dagobert', + role: 'user', + }, + { + email: 'dagobert@example.org', + }, + ), ]) await Promise.all([ @@ -236,97 +270,97 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] ]) await Promise.all([ - factory.create('Category', { + Factory.build('category', { id: 'cat1', name: 'Just For Fun', slug: 'just-for-fun', icon: 'smile', }), - factory.create('Category', { + Factory.build('category', { id: 'cat2', name: 'Happiness & Values', slug: 'happiness-values', icon: 'heart-o', }), - factory.create('Category', { + Factory.build('category', { id: 'cat3', name: 'Health & Wellbeing', slug: 'health-wellbeing', icon: 'medkit', }), - factory.create('Category', { + Factory.build('category', { id: 'cat4', name: 'Environment & Nature', slug: 'environment-nature', icon: 'tree', }), - factory.create('Category', { + Factory.build('category', { id: 'cat5', name: 'Animal Protection', slug: 'animal-protection', icon: 'paw', }), - factory.create('Category', { + Factory.build('category', { id: 'cat6', name: 'Human Rights & Justice', slug: 'human-rights-justice', icon: 'balance-scale', }), - factory.create('Category', { + Factory.build('category', { id: 'cat7', name: 'Education & Sciences', slug: 'education-sciences', icon: 'graduation-cap', }), - factory.create('Category', { + Factory.build('category', { id: 'cat8', name: 'Cooperation & Development', slug: 'cooperation-development', icon: 'users', }), - factory.create('Category', { + Factory.build('category', { id: 'cat9', name: 'Democracy & Politics', slug: 'democracy-politics', icon: 'university', }), - factory.create('Category', { + Factory.build('category', { id: 'cat10', name: 'Economy & Finances', slug: 'economy-finances', icon: 'money', }), - factory.create('Category', { + Factory.build('category', { id: 'cat11', name: 'Energy & Technology', slug: 'energy-technology', icon: 'flash', }), - factory.create('Category', { + Factory.build('category', { id: 'cat12', name: 'IT, Internet & Data Privacy', slug: 'it-internet-data-privacy', icon: 'mouse-pointer', }), - factory.create('Category', { + Factory.build('category', { id: 'cat13', name: 'Art, Culture & Sport', slug: 'art-culture-sport', icon: 'paint-brush', }), - factory.create('Category', { + Factory.build('category', { id: 'cat14', name: 'Freedom of Speech', slug: 'freedom-of-speech', icon: 'bullhorn', }), - factory.create('Category', { + Factory.build('category', { id: 'cat15', name: 'Consumption & Sustainability', slug: 'consumption-sustainability', icon: 'shopping-cart', }), - factory.create('Category', { + Factory.build('category', { id: 'cat16', name: 'Global Peace & Nonviolence', slug: 'global-peace-nonviolence', @@ -335,104 +369,164 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] ]) const [environment, nature, democracy, freedom] = await Promise.all([ - factory.create('Tag', { + Factory.build('tag', { id: 'Environment', }), - factory.create('Tag', { + Factory.build('tag', { id: 'Nature', }), - factory.create('Tag', { + Factory.build('tag', { id: 'Democracy', }), - factory.create('Tag', { + Factory.build('tag', { id: 'Freedom', }), ]) const [p0, p1, p3, p4, p5, p6, p9, p10, p11, p13, p14, p15] = await Promise.all([ - factory.create('Post', { - author: peterLustig, - id: 'p0', - language: sample(languages), - image: faker.image.unsplash.food(300, 169), - categoryIds: ['cat16'], - imageBlurred: true, - imageAspectRatio: 300 / 169, - }), - factory.create('Post', { - author: bobDerBaumeister, - id: 'p1', - language: sample(languages), - image: faker.image.unsplash.technology(300, 1500), - categoryIds: ['cat1'], - imageAspectRatio: 300 / 1500, - }), - factory.create('Post', { - author: huey, - id: 'p3', - language: sample(languages), - categoryIds: ['cat3'], - }), - factory.create('Post', { - author: dewey, - id: 'p4', - language: sample(languages), - categoryIds: ['cat4'], - }), - factory.create('Post', { - author: louie, - id: 'p5', - language: sample(languages), - categoryIds: ['cat5'], - }), - factory.create('Post', { - authorId: 'u1', - id: 'p6', - language: sample(languages), - image: faker.image.unsplash.buildings(300, 857), - categoryIds: ['cat6'], - imageAspectRatio: 300 / 857, - }), - factory.create('Post', { - author: huey, - id: 'p9', - language: sample(languages), - categoryIds: ['cat9'], - }), - factory.create('Post', { - author: dewey, - id: 'p10', - categoryIds: ['cat10'], - imageBlurred: true, - }), - factory.create('Post', { - author: louie, - id: 'p11', - language: sample(languages), - image: faker.image.unsplash.people(300, 901), - categoryIds: ['cat11'], - imageAspectRatio: 300 / 901, - }), - factory.create('Post', { - author: bobDerBaumeister, - id: 'p13', - language: sample(languages), - categoryIds: ['cat13'], - }), - factory.create('Post', { - author: jennyRostock, - id: 'p14', - language: sample(languages), - image: faker.image.unsplash.objects(300, 200), - categoryIds: ['cat14'], - imageAspectRatio: 300 / 450, - }), - factory.create('Post', { - author: huey, - id: 'p15', - language: sample(languages), - categoryIds: ['cat15'], - }), + Factory.build( + 'post', + { + id: 'p0', + language: sample(languages), + image: faker.image.unsplash.food(300, 169), + imageBlurred: true, + imageAspectRatio: 300 / 169, + }, + { + categoryIds: ['cat16'], + author: peterLustig, + }, + ), + Factory.build( + 'post', + { + id: 'p1', + language: sample(languages), + image: faker.image.unsplash.technology(300, 1500), + imageAspectRatio: 300 / 1500, + }, + { + categoryIds: ['cat1'], + author: bobDerBaumeister, + }, + ), + Factory.build( + 'post', + { + id: 'p3', + language: sample(languages), + }, + { + categoryIds: ['cat3'], + author: huey, + }, + ), + Factory.build( + 'post', + { + id: 'p4', + language: sample(languages), + }, + { + categoryIds: ['cat4'], + author: dewey, + }, + ), + Factory.build( + 'post', + { + id: 'p5', + language: sample(languages), + }, + { + categoryIds: ['cat5'], + author: louie, + }, + ), + Factory.build( + 'post', + { + id: 'p6', + language: sample(languages), + image: faker.image.unsplash.buildings(300, 857), + imageAspectRatio: 300 / 857, + }, + { + categoryIds: ['cat6'], + author: peterLustig, + }, + ), + Factory.build( + 'post', + { + id: 'p9', + language: sample(languages), + }, + { + categoryIds: ['cat9'], + author: huey, + }, + ), + Factory.build( + 'post', + { + id: 'p10', + imageBlurred: true, + }, + { + categoryIds: ['cat10'], + author: dewey, + }, + ), + Factory.build( + 'post', + { + id: 'p11', + language: sample(languages), + image: faker.image.unsplash.people(300, 901), + imageAspectRatio: 300 / 901, + }, + { + categoryIds: ['cat11'], + author: louie, + }, + ), + Factory.build( + 'post', + { + id: 'p13', + language: sample(languages), + }, + { + categoryIds: ['cat13'], + author: bobDerBaumeister, + }, + ), + Factory.build( + 'post', + { + id: 'p14', + language: sample(languages), + image: faker.image.unsplash.objects(300, 200), + imageAspectRatio: 300 / 450, + }, + { + categoryIds: ['cat14'], + author: jennyRostock, + }, + ), + Factory.build( + 'post', + { + id: 'p15', + language: sample(languages), + }, + { + categoryIds: ['cat15'], + author: huey, + }, + ), ]) authenticatedUser = await louie.toJson() @@ -554,61 +648,116 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] authenticatedUser = null const comments = await Promise.all([ - factory.create('Comment', { - author: jennyRostock, - id: 'c1', - postId: 'p1', - }), - factory.create('Comment', { - author: huey, - id: 'c2', - postId: 'p1', - }), - factory.create('Comment', { - author: louie, - id: 'c3', - postId: 'p3', - }), - factory.create('Comment', { - author: jennyRostock, - id: 'c5', - postId: 'p3', - }), - factory.create('Comment', { - author: peterLustig, - id: 'c6', - postId: 'p4', - }), - factory.create('Comment', { - author: jennyRostock, - id: 'c7', - postId: 'p2', - }), - factory.create('Comment', { - author: huey, - id: 'c8', - postId: 'p15', - }), - factory.create('Comment', { - author: dewey, - id: 'c9', - postId: 'p15', - }), - factory.create('Comment', { - author: louie, - id: 'c10', - postId: 'p15', - }), - factory.create('Comment', { - author: jennyRostock, - id: 'c11', - postId: 'p15', - }), - factory.create('Comment', { - author: jennyRostock, - id: 'c12', - postId: 'p15', - }), + Factory.build( + 'comment', + { + id: 'c1', + }, + { + author: jennyRostock, + postId: 'p1', + }, + ), + Factory.build( + 'comment', + { + id: 'c2', + }, + { + author: huey, + postId: 'p1', + }, + ), + Factory.build( + 'comment', + { + id: 'c3', + }, + { + author: louie, + postId: 'p3', + }, + ), + Factory.build( + 'comment', + { + id: 'c5', + }, + { + author: jennyRostock, + postId: 'p3', + }, + ), + Factory.build( + 'comment', + { + id: 'c6', + }, + { + author: peterLustig, + postId: 'p4', + }, + ), + Factory.build( + 'comment', + { + id: 'c7', + }, + { + author: jennyRostock, + postId: 'p2', + }, + ), + Factory.build( + 'comment', + { + id: 'c8', + }, + { + author: huey, + postId: 'p15', + }, + ), + Factory.build( + 'comment', + { + id: 'c9', + }, + { + author: dewey, + postId: 'p15', + }, + ), + Factory.build( + 'comment', + { + id: 'c10', + }, + { + author: louie, + postId: 'p15', + }, + ), + Factory.build( + 'comment', + { + id: 'c11', + }, + { + author: jennyRostock, + postId: 'p15', + }, + ), + Factory.build( + 'comment', + { + id: 'c12', + }, + { + author: jennyRostock, + postId: 'p15', + }, + ), ]) const trollingComment = comments[0] @@ -675,10 +824,10 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] ]) const reports = await Promise.all([ - factory.create('Report'), - factory.create('Report'), - factory.create('Report'), - factory.create('Report'), + Factory.build('report'), + Factory.build('report'), + Factory.build('report'), + Factory.build('report'), ]) const reportAgainstDagobert = reports[0] const reportAgainstTrollingPost = reports[1] @@ -784,231 +933,338 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl'] trollingComment.update({ disabled: true, updatedAt: new Date().toISOString(), closed: true }), ]) + await Promise.all([...Array(30).keys()].map(() => Factory.build('user'))) + await Promise.all( - [...Array(30).keys()].map(i => { - return factory.create('User') - }), + [...Array(30).keys()].map(() => + Factory.build( + 'post', + { + image: faker.image.unsplash.objects(), + }, + { + categoryIds: ['cat1'], + author: jennyRostock, + }, + ), + ), ) await Promise.all( - [...Array(30).keys()].map(() => { - return factory.create('Post', { - author: jennyRostock, - image: faker.image.unsplash.objects(), - }) - }), + [...Array(6).keys()].map(() => + Factory.build( + 'comment', + {}, + { + author: jennyRostock, + postId: 'p2', + }, + ), + ), ) await Promise.all( - [...Array(6).keys()].map(() => { - return factory.create('Comment', { - author: jennyRostock, - postId: 'p2', - }) - }), + [...Array(4).keys()].map(() => + Factory.build( + 'comment', + 4, + {}, + { + author: jennyRostock, + postId: 'p15', + }, + ), + ), ) await Promise.all( - [...Array(4).keys()].map(() => { - return factory.create('Comment', { - author: jennyRostock, - postId: 'p15', - }) - }), + [...Array(2).keys()].map(() => + Factory.build( + 'comment', + {}, + { + author: jennyRostock, + postId: 'p4', + }, + ), + ), ) await Promise.all( - [...Array(2).keys()].map(() => { - return factory.create('Comment', { - author: jennyRostock, - postId: 'p4', - }) - }), + [...Array(21).keys()].map(() => + Factory.build( + 'post', + { + image: faker.image.unsplash.buildings(), + }, + { + categoryIds: ['cat1'], + author: peterLustig, + }, + ), + ), ) await Promise.all( - [...Array(21).keys()].map(() => { - return factory.create('Post', { - author: peterLustig, - image: faker.image.unsplash.buildings(), - }) - }), + [...Array(3).keys()].map(() => + Factory.build( + 'comment', + {}, + { + author: peterLustig, + postId: 'p4', + }, + ), + ), ) await Promise.all( - [...Array(3).keys()].map(() => { - return factory.create('Comment', { - author: peterLustig, - postId: 'p4', - }) - }), + [...Array(3).keys()].map(() => + Factory.build( + 'comment', + {}, + { + author: peterLustig, + postId: 'p14', + }, + ), + ), ) await Promise.all( - [...Array(5).keys()].map(() => { - return factory.create('Comment', { - author: peterLustig, - postId: 'p14', - }) - }), + [...Array(6).keys()].map(() => + Factory.build( + 'comment', + {}, + { + author: peterLustig, + postId: 'p0', + }, + ), + ), ) await Promise.all( - [...Array(6).keys()].map(() => { - return factory.create('Comment', { - author: peterLustig, - postId: 'p0', - }) - }), + [...Array(11).keys()].map(() => + Factory.build( + 'post', + { + image: faker.image.unsplash.food(), + }, + { + categoryIds: ['cat1'], + author: dewey, + }, + ), + ), ) await Promise.all( - [...Array(11).keys()].map(() => { - return factory.create('Post', { - author: dewey, - image: faker.image.unsplash.food(), - }) - }), + [...Array(7).keys()].map(() => + Factory.build( + 'comment', + {}, + { + author: dewey, + postId: 'p2', + }, + ), + ), ) await Promise.all( - [...Array(7).keys()].map(() => { - return factory.create('Comment', { - author: dewey, - postId: 'p2', - }) - }), + [...Array(5).keys()].map(() => + Factory.build( + 'comment', + {}, + { + author: dewey, + postId: 'p6', + }, + ), + ), ) await Promise.all( - [...Array(5).keys()].map(() => { - return factory.create('Comment', { - author: dewey, - postId: 'p6', - }) - }), + [...Array(2).keys()].map(() => + Factory.build( + 'comment', + {}, + { + author: dewey, + postId: 'p9', + }, + ), + ), ) await Promise.all( - [...Array(2).keys()].map(() => { - return factory.create('Comment', { - author: dewey, - postId: 'p9', - }) - }), + [...Array(16).keys()].map(() => + Factory.build( + 'post', + { + image: faker.image.unsplash.technology(), + }, + { + categoryIds: ['cat1'], + author: louie, + }, + ), + ), ) await Promise.all( - [...Array(16).keys()].map(() => { - return factory.create('Post', { - author: louie, - image: faker.image.unsplash.technology(), - }) - }), + [...Array(4).keys()].map(() => + Factory.build( + 'comment', + {}, + { + postId: 'p1', + author: louie, + }, + ), + ), ) await Promise.all( - [...Array(4).keys()].map(() => { - return factory.create('Comment', { - author: louie, - postId: 'p1', - }) - }), + [...Array(8).keys()].map(() => + Factory.build( + 'comment', + {}, + { + author: louie, + postId: 'p10', + }, + ), + ), ) await Promise.all( - [...Array(8).keys()].map(() => { - return factory.create('Comment', { - author: louie, - postId: 'p10', - }) - }), + [...Array(5).keys()].map(() => + Factory.build( + 'comment', + {}, + { + author: louie, + postId: 'p13', + }, + ), + ), ) await Promise.all( - [...Array(5).keys()].map(() => { - return factory.create('Comment', { - author: louie, - postId: 'p13', - }) - }), + [...Array(45).keys()].map(() => + Factory.build( + 'post', + { + image: faker.image.unsplash.people(), + }, + { + categoryIds: ['cat1'], + author: bobDerBaumeister, + }, + ), + ), ) await Promise.all( - [...Array(45).keys()].map(() => { - return factory.create('Post', { - author: bobDerBaumeister, - image: faker.image.unsplash.people(), - }) - }), + [...Array(2).keys()].map(() => + Factory.build( + 'comment', + {}, + { + author: bobDerBaumeister, + postId: 'p2', + }, + ), + ), ) await Promise.all( - [...Array(2).keys()].map(() => { - return factory.create('Comment', { - author: bobDerBaumeister, - postId: 'p2', - }) - }), + [...Array(3).keys()].map(() => + Factory.build( + 'comment', + {}, + { + author: bobDerBaumeister, + postId: 'p12', + }, + ), + ), ) await Promise.all( - [...Array(3).keys()].map(() => { - return factory.create('Comment', { - author: bobDerBaumeister, - postId: 'p12', - }) - }), + [...Array(7).keys()].map(() => + Factory.build( + 'comment', + {}, + { + author: bobDerBaumeister, + postId: 'p13', + }, + ), + ), ) await Promise.all( - [...Array(7).keys()].map(() => { - return factory.create('Comment', { - author: bobDerBaumeister, - postId: 'p13', - }) - }), + [...Array(8).keys()].map(() => + Factory.build( + 'post', + { + image: faker.image.unsplash.nature(), + }, + { + categoryIds: ['cat1'], + author: huey, + }, + ), + ), ) await Promise.all( - [...Array(8).keys()].map(() => { - return factory.create('Post', { - author: huey, - image: faker.image.unsplash.nature(), - }) - }), + [...Array(6).keys()].map(() => + Factory.build( + 'comment', + {}, + { + author: huey, + postId: 'p0', + }, + ), + ), ) await Promise.all( - [...Array(6).keys()].map(() => { - return factory.create('Comment', { - author: huey, - postId: 'p0', - }) - }), + [...Array(8).keys()].map(() => + Factory.build( + 'comment', + {}, + { + author: huey, + postId: 'p13', + }, + ), + ), ) await Promise.all( - [...Array(8).keys()].map(() => { - return factory.create('Comment', { - author: huey, - postId: 'p13', - }) - }), + [...Array(8).keys()].map(() => + Factory.build( + 'comment', + {}, + { + author: huey, + postId: 'p15', + }, + ), + ), ) - await Promise.all( - [...Array(9).keys()].map(() => { - return factory.create('Comment', { - author: huey, - postId: 'p15', - }) - }), - ) - - await factory.create('Donations') + await Factory.build('donations') /* eslint-disable-next-line no-console */ console.log('Seeded Data...') + await driver.close() + await neode.close() process.exit(0) } catch (err) { /* eslint-disable-next-line no-console */ diff --git a/backend/src/factories/badges.js b/backend/src/factories/badges.js deleted file mode 100644 index 5f0482460..000000000 --- a/backend/src/factories/badges.js +++ /dev/null @@ -1,15 +0,0 @@ -export default function create() { - return { - factory: async ({ args, neodeInstance }) => { - const defaults = { - type: 'crowdfunding', - status: 'permanent', - } - args = { - ...defaults, - ...args, - } - return neodeInstance.create('Badge', args) - }, - } -} diff --git a/backend/src/factories/categories.js b/backend/src/factories/categories.js deleted file mode 100644 index d3f5fed21..000000000 --- a/backend/src/factories/categories.js +++ /dev/null @@ -1,18 +0,0 @@ -import uuid from 'uuid/v4' - -export default function create() { - return { - factory: async ({ args, neodeInstance }) => { - const defaults = { - id: uuid(), - icon: 'img/badges/fundraisingbox_de_airship.svg', - name: 'Some category name', - } - args = { - ...defaults, - ...args, - } - return neodeInstance.create('Category', args) - }, - } -} diff --git a/backend/src/factories/comments.js b/backend/src/factories/comments.js deleted file mode 100644 index de3390e1a..000000000 --- a/backend/src/factories/comments.js +++ /dev/null @@ -1,38 +0,0 @@ -import faker from 'faker' -import uuid from 'uuid/v4' - -export default function create() { - return { - factory: async ({ args, neodeInstance, factoryInstance }) => { - const defaults = { - id: uuid(), - content: [faker.lorem.sentence(), faker.lorem.sentence()].join('. '), - } - args = { - ...defaults, - ...args, - } - args.contentExcerpt = args.contentExcerpt || args.content - - let { post, postId } = args - delete args.post - delete args.postId - if (post && postId) throw new Error('You provided both post and postId') - if (postId) post = await neodeInstance.find('Post', postId) - post = post || (await factoryInstance.create('Post')) - - let { author, authorId } = args - delete args.author - delete args.authorId - if (author && authorId) throw new Error('You provided both author and authorId') - if (authorId) author = await neodeInstance.find('User', authorId) - author = author || (await factoryInstance.create('User')) - - delete args.author - const comment = await neodeInstance.create('Comment', args) - await comment.relateTo(post, 'post') - await comment.relateTo(author, 'author') - return comment - }, - } -} diff --git a/backend/src/factories/donations.js b/backend/src/factories/donations.js deleted file mode 100644 index e22cdb6d7..000000000 --- a/backend/src/factories/donations.js +++ /dev/null @@ -1,18 +0,0 @@ -import uuid from 'uuid/v4' - -export default function create() { - return { - factory: async ({ args, neodeInstance }) => { - const defaults = { - id: uuid(), - goal: 15000, - progress: 0, - } - args = { - ...defaults, - ...args, - } - return neodeInstance.create('Donations', args) - }, - } -} diff --git a/backend/src/factories/emailAddresses.js b/backend/src/factories/emailAddresses.js deleted file mode 100644 index 41b1fe96c..000000000 --- a/backend/src/factories/emailAddresses.js +++ /dev/null @@ -1,22 +0,0 @@ -import faker from 'faker' - -export function defaults({ args }) { - const defaults = { - email: faker.internet.email(), - verifiedAt: new Date().toISOString(), - } - args = { - ...defaults, - ...args, - } - return args -} - -export default function create() { - return { - factory: async ({ args, neodeInstance }) => { - args = defaults({ args }) - return neodeInstance.create('EmailAddress', args) - }, - } -} diff --git a/backend/src/factories/index.js b/backend/src/factories/index.js deleted file mode 100644 index c3ab14f64..000000000 --- a/backend/src/factories/index.js +++ /dev/null @@ -1,63 +0,0 @@ -import { getDriver, getNeode } from '../db/neo4j' - -const factories = { - Badge: require('./badges.js').default, - User: require('./users.js').default, - Post: require('./posts.js').default, - Comment: require('./comments.js').default, - Category: require('./categories.js').default, - Tag: require('./tags.js').default, - SocialMedia: require('./socialMedia.js').default, - Location: require('./locations.js').default, - EmailAddress: require('./emailAddresses.js').default, - UnverifiedEmailAddress: require('./unverifiedEmailAddresses.js').default, - Donations: require('./donations.js').default, - Report: require('./reports.js').default, -} - -export const cleanDatabase = async (options = {}) => { - const { driver = getDriver() } = options - const session = driver.session() - try { - await session.writeTransaction(transaction => { - return transaction.run( - ` - MATCH (everything) - DETACH DELETE everything - `, - ) - }) - } finally { - session.close() - } -} - -export default function Factory(options = {}) { - const { neo4jDriver = getDriver(), neodeInstance = getNeode() } = options - - const result = { - neo4jDriver, - factories, - lastResponse: null, - neodeInstance, - async create(node, args = {}) { - const { factory } = this.factories[node](args) - this.lastResponse = await factory({ - args, - neodeInstance, - factoryInstance: this, - }) - return this.lastResponse - }, - - async cleanDatabase() { - this.lastResponse = await cleanDatabase({ - driver: this.neo4jDriver, - }) - return this - }, - } - result.create.bind(result) - result.cleanDatabase.bind(result) - return result -} diff --git a/backend/src/factories/locations.js b/backend/src/factories/locations.js deleted file mode 100644 index 99b666de8..000000000 --- a/backend/src/factories/locations.js +++ /dev/null @@ -1,24 +0,0 @@ -export default function create() { - return { - factory: async ({ args, neodeInstance }) => { - const defaults = { - name: 'Germany', - namePT: 'Alemanha', - nameDE: 'Deutschland', - nameES: 'Alemania', - nameNL: 'Duitsland', - namePL: 'Niemcy', - nameFR: 'Allemagne', - nameIT: 'Germania', - nameEN: 'Germany', - id: 'country.10743216036480410', - type: 'country', - } - args = { - ...defaults, - ...args, - } - return neodeInstance.create('Location', args) - }, - } -} diff --git a/backend/src/factories/posts.js b/backend/src/factories/posts.js deleted file mode 100644 index d997b738f..000000000 --- a/backend/src/factories/posts.js +++ /dev/null @@ -1,89 +0,0 @@ -import faker from 'faker' -import slugify from 'slug' -import uuid from 'uuid/v4' - -export default function create() { - return { - factory: async ({ args, neodeInstance, factoryInstance }) => { - const defaults = { - id: uuid(), - title: faker.lorem.sentence(), - content: [ - faker.lorem.sentence(), - faker.lorem.sentence(), - faker.lorem.sentence(), - faker.lorem.sentence(), - faker.lorem.sentence(), - ].join('. '), - image: faker.image.unsplash.imageUrl(), - visibility: 'public', - deleted: false, - categoryIds: [], - imageBlurred: false, - imageAspectRatio: 1.333, - pinned: null, - } - args = { - ...defaults, - ...args, - } - // Convert false to null - args.pinned = args.pinned || null - - args.slug = args.slug || slugify(args.title, { lower: true }) - args.contentExcerpt = args.contentExcerpt || args.content - - let { categories, categoryIds } = args - delete args.categories - delete args.categoryIds - if (categories && categoryIds) throw new Error('You provided both categories and categoryIds') - if (categoryIds) - categories = await Promise.all(categoryIds.map(id => neodeInstance.find('Category', id))) - categories = categories || (await Promise.all([factoryInstance.create('Category')])) - const { tagIds = [] } = args - delete args.tags - const tags = await Promise.all( - tagIds.map(t => { - return neodeInstance.find('Tag', t) - }), - ) - - let { author, authorId } = args - delete args.author - delete args.authorId - if (author && authorId) throw new Error('You provided both author and authorId') - if (authorId) author = await neodeInstance.find('User', authorId) - author = author || (await factoryInstance.create('User')) - const post = await neodeInstance.create('Post', args) - - const { commentContent } = args - let comment - delete args.commentContent - if (commentContent) - comment = await factoryInstance.create('Comment', { - contentExcerpt: commentContent, - post, - author, - }) - - await post.relateTo(author, 'author') - if (comment) await post.relateTo(comment, 'comments') - - if (args.pinned) { - args.pinnedAt = args.pinnedAt || new Date().toISOString() - if (!args.pinnedBy) { - const admin = await factoryInstance.create('User', { - role: 'admin', - updatedAt: new Date().toISOString(), - }) - await admin.relateTo(post, 'pinned') - args.pinnedBy = admin - } - } - - await Promise.all(categories.map(c => c.relateTo(post, 'post'))) - await Promise.all(tags.map(t => t.relateTo(post, 'post'))) - return post - }, - } -} diff --git a/backend/src/factories/reports.js b/backend/src/factories/reports.js deleted file mode 100644 index e2d5ec4dc..000000000 --- a/backend/src/factories/reports.js +++ /dev/null @@ -1,7 +0,0 @@ -export default function create() { - return { - factory: async ({ args, neodeInstance }) => { - return neodeInstance.create('Report', args) - }, - } -} diff --git a/backend/src/factories/socialMedia.js b/backend/src/factories/socialMedia.js deleted file mode 100644 index 49a237cef..000000000 --- a/backend/src/factories/socialMedia.js +++ /dev/null @@ -1,14 +0,0 @@ -export default function create() { - return { - factory: async ({ args, neodeInstance }) => { - const defaults = { - url: 'https://mastodon.social/@Gargron', - } - args = { - ...defaults, - ...args, - } - return neodeInstance.create('SocialMedia', args) - }, - } -} diff --git a/backend/src/factories/tags.js b/backend/src/factories/tags.js deleted file mode 100644 index 9005d1406..000000000 --- a/backend/src/factories/tags.js +++ /dev/null @@ -1,12 +0,0 @@ -export default function create() { - return { - factory: async ({ args, neodeInstance }) => { - const defaults = { name: '#human-connection' } - args = { - ...defaults, - ...args, - } - return neodeInstance.create('Tag', args) - }, - } -} diff --git a/backend/src/factories/unverifiedEmailAddresses.js b/backend/src/factories/unverifiedEmailAddresses.js deleted file mode 100644 index 94e32af6e..000000000 --- a/backend/src/factories/unverifiedEmailAddresses.js +++ /dev/null @@ -1,10 +0,0 @@ -import { defaults } from './emailAddresses.js' - -export default function create() { - return { - factory: async ({ args, neodeInstance }) => { - args = defaults({ args }) - return neodeInstance.create('UnverifiedEmailAddress', args) - }, - } -} diff --git a/backend/src/factories/users.js b/backend/src/factories/users.js deleted file mode 100644 index 57f69b76b..000000000 --- a/backend/src/factories/users.js +++ /dev/null @@ -1,44 +0,0 @@ -import faker from 'faker' -import uuid from 'uuid/v4' -import encryptPassword from '../helpers/encryptPassword' -import slugify from 'slug' - -export default function create() { - return { - factory: async ({ args, neodeInstance, factoryInstance }) => { - const defaults = { - id: uuid(), - name: faker.name.findName(), - email: faker.internet.email(), - password: '1234', - role: 'user', - avatar: faker.internet.avatar(), - about: faker.lorem.paragraph(), - termsAndConditionsAgreedVersion: '0.0.1', - termsAndConditionsAgreedAt: '2019-08-01T10:47:19.212Z', - allowEmbedIframes: false, - showShoutsPublicly: false, - locale: 'en', - } - defaults.slug = slugify(defaults.name, { lower: true }) - args = { - ...defaults, - ...args, - } - args = await encryptPassword(args) - const user = await neodeInstance.create('User', args) - - let email - if (typeof args.email === 'object') { - // probably a neode node - email = args.email - } else { - email = await factoryInstance.create('EmailAddress', { email: args.email }) - } - - await user.relateTo(email, 'primaryEmail') - await email.relateTo(user, 'belongsTo') - return user - }, - } -} diff --git a/backend/src/jwt/decode.spec.js b/backend/src/jwt/decode.spec.js index 71444a3e5..aa8ff0674 100644 --- a/backend/src/jwt/decode.spec.js +++ b/backend/src/jwt/decode.spec.js @@ -1,8 +1,7 @@ -import Factory from '../factories/index' +import Factory, { cleanDatabase } from '../db/factories' import { getDriver, getNeode } from '../db/neo4j' import decode from './decode' -const factory = Factory() const driver = getDriver() const neode = getNeode() @@ -26,7 +25,7 @@ export const validAuthorizationHeader = 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoidXNlciIsImxvY2F0aW9uTmFtZSI6bnVsbCwibmFtZSI6Ikplbm55IFJvc3RvY2siLCJhYm91dCI6bnVsbCwiYXZhdGFyIjoiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL3VpZmFjZXMvZmFjZXMvdHdpdHRlci9zYXNoYV9zaGVzdGFrb3YvMTI4LmpwZyIsImlkIjoidTMiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5vcmciLCJzbHVnIjoiamVubnktcm9zdG9jayIsImlhdCI6MTU1MDg0NjY4MCwiZXhwIjoxNjM3MjQ2NjgwLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjQwMDAiLCJzdWIiOiJ1MyJ9.eZ_mVKas4Wzoc_JrQTEWXyRn7eY64cdIg4vqQ-F_7Jc' afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('decode', () => { @@ -65,14 +64,19 @@ describe('decode', () => { describe('and corresponding user in the database', () => { let user beforeEach(async () => { - user = await factory.create('User', { - role: 'user', - name: 'Jenny Rostock', - avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/sasha_shestakov/128.jpg', - id: 'u3', - email: 'user@example.org', - slug: 'jenny-rostock', - }) + user = await Factory.build( + 'user', + { + role: 'user', + name: 'Jenny Rostock', + avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/sasha_shestakov/128.jpg', + id: 'u3', + slug: 'jenny-rostock', + }, + { + email: 'user@example.org', + }, + ) }) it('returns user object except email', async () => { diff --git a/backend/src/middleware/hashtags/hashtagsMiddleware.spec.js b/backend/src/middleware/hashtags/hashtagsMiddleware.spec.js index 2247e692d..be9039a6f 100644 --- a/backend/src/middleware/hashtags/hashtagsMiddleware.spec.js +++ b/backend/src/middleware/hashtags/hashtagsMiddleware.spec.js @@ -1,5 +1,5 @@ import { gql } from '../../helpers/jest' -import Factory from '../../factories' +import { cleanDatabase } from '../../db/factories' import { createTestClient } from 'apollo-server-testing' import { getNeode, getDriver } from '../../db/neo4j' import createServer from '../../server' @@ -9,7 +9,6 @@ let query let mutate let hashtagingUser let authenticatedUser -const factory = Factory() const driver = getDriver() const neode = getNeode() const categoryIds = ['cat9'] @@ -48,13 +47,18 @@ beforeAll(() => { }) beforeEach(async () => { - hashtagingUser = await neode.create('User', { - id: 'you', - name: 'Al Capone', - slug: 'al-capone', - email: 'test@example.org', - password: '1234', - }) + hashtagingUser = await neode.create( + 'User', + { + id: 'you', + name: 'Al Capone', + slug: 'al-capone', + }, + { + password: '1234', + email: 'test@example.org', + }, + ) await neode.create('Category', { id: 'cat9', name: 'Democracy & Politics', @@ -63,7 +67,7 @@ beforeEach(async () => { }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('hashtags', () => { diff --git a/backend/src/middleware/notifications/notificationsMiddleware.spec.js b/backend/src/middleware/notifications/notificationsMiddleware.spec.js index 136388b88..95c0037b8 100644 --- a/backend/src/middleware/notifications/notificationsMiddleware.spec.js +++ b/backend/src/middleware/notifications/notificationsMiddleware.spec.js @@ -1,11 +1,10 @@ import { gql } from '../../helpers/jest' -import Factory from '../../factories' +import { cleanDatabase } from '../../db/factories' import { createTestClient } from 'apollo-server-testing' import { getNeode, getDriver } from '../../db/neo4j' import createServer from '../../server' let server, query, mutate, notifiedUser, authenticatedUser -const factory = Factory() const driver = getDriver() const neode = getNeode() const categoryIds = ['cat9'] @@ -36,7 +35,7 @@ const createCommentMutation = gql` ` beforeAll(async () => { - await factory.cleanDatabase() + await cleanDatabase() const createServerResult = createServer({ context: () => { return { @@ -53,13 +52,18 @@ beforeAll(async () => { }) beforeEach(async () => { - notifiedUser = await neode.create('User', { - id: 'you', - name: 'Al Capone', - slug: 'al-capone', - email: 'test@example.org', - password: '1234', - }) + notifiedUser = await neode.create( + 'User', + { + id: 'you', + name: 'Al Capone', + slug: 'al-capone', + }, + { + email: 'test@example.org', + password: '1234', + }, + ) await neode.create('Category', { id: 'cat9', name: 'Democracy & Politics', @@ -68,7 +72,7 @@ beforeEach(async () => { }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('notifications', () => { @@ -143,13 +147,18 @@ describe('notifications', () => { describe('commenter is not me', () => { beforeEach(async () => { commentContent = 'Commenters comment.' - commentAuthor = await neode.create('User', { - id: 'commentAuthor', - name: 'Mrs Comment', - slug: 'mrs-comment', - email: 'commentauthor@example.org', - password: '1234', - }) + commentAuthor = await neode.create( + 'User', + { + id: 'commentAuthor', + name: 'Mrs Comment', + slug: 'mrs-comment', + }, + { + email: 'commentauthor@example.org', + password: '1234', + }, + ) }) it('sends me a notification', async () => { @@ -224,13 +233,18 @@ describe('notifications', () => { }) beforeEach(async () => { - postAuthor = await neode.create('User', { - id: 'postAuthor', - name: 'Mrs Post', - slug: 'mrs-post', - email: 'post-author@example.org', - password: '1234', - }) + postAuthor = await neode.create( + 'User', + { + id: 'postAuthor', + name: 'Mrs Post', + slug: 'mrs-post', + }, + { + email: 'post-author@example.org', + password: '1234', + }, + ) }) describe('mentions me in a post', () => { @@ -428,23 +442,33 @@ describe('notifications', () => { beforeEach(async () => { commentContent = 'One mention about me with @al-capone.' - commentAuthor = await neode.create('User', { - id: 'commentAuthor', - name: 'Mrs Comment', - slug: 'mrs-comment', - email: 'comment-author@example.org', - password: '1234', - }) + commentAuthor = await neode.create( + 'User', + { + id: 'commentAuthor', + name: 'Mrs Comment', + slug: 'mrs-comment', + }, + { + email: 'comment-author@example.org', + password: '1234', + }, + ) }) it('sends only one notification with reason mentioned_in_comment', async () => { - postAuthor = await neode.create('User', { - id: 'MrPostAuthor', - name: 'Mr Author', - slug: 'mr-author', - email: 'post-author@example.org', - password: '1234', - }) + postAuthor = await neode.create( + 'User', + { + id: 'MrPostAuthor', + name: 'Mr Author', + slug: 'mr-author', + }, + { + email: 'post-author@example.org', + password: '1234', + }, + ) await createCommentOnPostAction() const expected = expect.objectContaining({ @@ -514,13 +538,18 @@ describe('notifications', () => { await postAuthor.relateTo(notifiedUser, 'blocked') commentContent = 'One mention about me with @al-capone.' - commentAuthor = await neode.create('User', { - id: 'commentAuthor', - name: 'Mrs Comment', - slug: 'mrs-comment', - email: 'comment-author@example.org', - password: '1234', - }) + commentAuthor = await neode.create( + 'User', + { + id: 'commentAuthor', + name: 'Mrs Comment', + slug: 'mrs-comment', + }, + { + email: 'comment-author@example.org', + password: '1234', + }, + ) }) it('sends no notification', async () => { diff --git a/backend/src/middleware/orderByMiddleware.spec.js b/backend/src/middleware/orderByMiddleware.spec.js index 8d92a5b5d..91caa1f54 100644 --- a/backend/src/middleware/orderByMiddleware.spec.js +++ b/backend/src/middleware/orderByMiddleware.spec.js @@ -1,10 +1,9 @@ import { gql } from '../helpers/jest' -import Factory from '../factories' +import { cleanDatabase } from '../db/factories' import { getNeode, getDriver } from '../db/neo4j' import { createTestClient } from 'apollo-server-testing' import createServer from '../server' -const factory = Factory() const neode = getNeode() const driver = getDriver() @@ -27,7 +26,7 @@ beforeEach(async () => { }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('Query', () => { diff --git a/backend/src/middleware/permissionsMiddleware.spec.js b/backend/src/middleware/permissionsMiddleware.spec.js index a4f13ea0c..3c307348d 100644 --- a/backend/src/middleware/permissionsMiddleware.spec.js +++ b/backend/src/middleware/permissionsMiddleware.spec.js @@ -1,10 +1,9 @@ import { createTestClient } from 'apollo-server-testing' import createServer from '../server' -import Factory from '../factories' +import Factory, { cleanDatabase } from '../db/factories' import { gql } from '../helpers/jest' import { getDriver, getNeode } from '../db/neo4j' -const factory = Factory() const instance = getNeode() const driver = getDriver() @@ -20,7 +19,7 @@ const userQuery = gql` describe('authorization', () => { beforeAll(async () => { - await factory.cleanDatabase() + await cleanDatabase() const { server } = createServer({ context: () => ({ driver, @@ -34,34 +33,54 @@ describe('authorization', () => { describe('given two existing users', () => { beforeEach(async () => { ;[owner, anotherRegularUser, administrator, moderator] = await Promise.all([ - factory.create('User', { - email: 'owner@example.org', - name: 'Owner', - password: 'iamtheowner', - }), - factory.create('User', { - email: 'another.regular.user@example.org', - name: 'Another Regular User', - password: 'else', - }), - factory.create('User', { - email: 'admin@example.org', - name: 'Admin', - password: 'admin', - role: 'admin', - }), - factory.create('User', { - email: 'moderator@example.org', - name: 'Moderator', - password: 'moderator', - role: 'moderator', - }), + Factory.build( + 'user', + { + name: 'Owner', + }, + { + email: 'owner@example.org', + password: 'iamtheowner', + }, + ), + Factory.build( + 'user', + { + name: 'Another Regular User', + }, + { + email: 'another.regular.user@example.org', + password: 'else', + }, + ), + Factory.build( + 'user', + { + name: 'Admin', + role: 'admin', + }, + { + email: 'admin@example.org', + password: 'admin', + }, + ), + Factory.build( + 'user', + { + name: 'Moderator', + role: 'moderator', + }, + { + email: 'moderator@example.org', + password: 'moderator', + }, + ), ]) variables = {} }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('access email address', () => { diff --git a/backend/src/middleware/slugifyMiddleware.spec.js b/backend/src/middleware/slugifyMiddleware.spec.js index cf9f0941c..e522136d6 100644 --- a/backend/src/middleware/slugifyMiddleware.spec.js +++ b/backend/src/middleware/slugifyMiddleware.spec.js @@ -1,11 +1,9 @@ -import Factory from '../factories' +import Factory, { cleanDatabase } from '../db/factories' import { gql } from '../helpers/jest' import { getNeode, getDriver } from '../db/neo4j' import createServer from '../server' import { createTestClient } from 'apollo-server-testing' -const factory = Factory() - let mutate let authenticatedUser let variables @@ -28,14 +26,18 @@ beforeAll(() => { beforeEach(async () => { variables = {} - const admin = await factory.create('User', { + const admin = await Factory.build('user', { role: 'admin', }) - await factory.create('User', { - email: 'someone@example.org', - password: '1234', - }) - await factory.create('Category', { + await Factory.build( + 'user', + {}, + { + email: 'someone@example.org', + password: '1234', + }, + ) + await Factory.build('category', { id: 'cat9', name: 'Democracy & Politics', icon: 'university', @@ -44,7 +46,7 @@ beforeEach(async () => { }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('slugifyMiddleware', () => { @@ -84,12 +86,17 @@ describe('slugifyMiddleware', () => { describe('if slug exists', () => { beforeEach(async () => { - await factory.create('Post', { - title: 'Pre-existing post', - slug: 'pre-existing-post', - content: 'as Someone else content', - categoryIds, - }) + await Factory.build( + 'post', + { + title: 'Pre-existing post', + slug: 'pre-existing-post', + content: 'as Someone else content', + }, + { + categoryIds, + }, + ) }) it('chooses another slug', async () => { @@ -190,7 +197,7 @@ describe('slugifyMiddleware', () => { describe('given a user has signed up with their email address', () => { beforeEach(async () => { - await factory.create('EmailAddress', { + await Factory.build('emailAddress', { email: '123@example.org', nonce: '123456', verifiedAt: null, @@ -214,7 +221,7 @@ describe('slugifyMiddleware', () => { describe('if slug exists', () => { beforeEach(async () => { - await factory.create('User', { + await Factory.build('user', { name: 'I am a user', slug: 'i-am-a-user', }) diff --git a/backend/src/middleware/softDelete/softDeleteMiddleware.spec.js b/backend/src/middleware/softDelete/softDeleteMiddleware.spec.js index 6e1735af2..de5626d14 100644 --- a/backend/src/middleware/softDelete/softDeleteMiddleware.spec.js +++ b/backend/src/middleware/softDelete/softDeleteMiddleware.spec.js @@ -1,10 +1,9 @@ -import Factory from '../../factories' +import Factory, { cleanDatabase } from '../../db/factories' import { gql } from '../../helpers/jest' import { getNeode, getDriver } from '../../db/neo4j' import createServer from '../../server' import { createTestClient } from 'apollo-server-testing' -const factory = Factory() const neode = getNeode() const driver = getDriver() @@ -18,13 +17,18 @@ const action = () => { beforeAll(async () => { // For performance reasons we do this only once const users = await Promise.all([ - factory.create('User', { id: 'u1', role: 'user' }), - factory.create('User', { - id: 'm1', - role: 'moderator', - password: '1234', - }), - factory.create('User', { + Factory.build('user', { id: 'u1', role: 'user' }), + Factory.build( + 'user', + { + id: 'm1', + role: 'moderator', + }, + { + password: '1234', + }, + ), + Factory.build('user', { id: 'u2', role: 'user', name: 'Offensive Name', @@ -45,48 +49,73 @@ beforeAll(async () => { await Promise.all([ user.relateTo(troll, 'following'), - factory.create('Post', { - author: user, - id: 'p1', - title: 'Deleted post', - slug: 'deleted-post', - deleted: true, - categoryIds, - }), - factory.create('Post', { - author: user, - id: 'p3', - title: 'Publicly visible post', - slug: 'publicly-visible-post', - deleted: false, - categoryIds, - }), + Factory.build( + 'post', + { + id: 'p1', + title: 'Deleted post', + slug: 'deleted-post', + deleted: true, + }, + { + author: user, + categoryIds, + }, + ), + Factory.build( + 'post', + { + id: 'p3', + title: 'Publicly visible post', + slug: 'publicly-visible-post', + deleted: false, + }, + { + author: user, + categoryIds, + }, + ), ]) const resources = await Promise.all([ - factory.create('Comment', { - author: user, - id: 'c2', - postId: 'p3', - content: 'Enabled comment on public post', - }), - factory.create('Post', { - id: 'p2', - author: troll, - title: 'Disabled post', - content: 'This is an offensive post content', - contentExcerpt: 'This is an offensive post content', - image: '/some/offensive/image.jpg', - deleted: false, - categoryIds, - }), - factory.create('Comment', { - id: 'c1', - author: troll, - postId: 'p3', - content: 'Disabled comment', - contentExcerpt: 'Disabled comment', - }), + Factory.build( + 'comment', + { + id: 'c2', + content: 'Enabled comment on public post', + }, + { + author: user, + postId: 'p3', + }, + ), + Factory.build( + 'post', + { + id: 'p2', + title: 'Disabled post', + content: 'This is an offensive post content', + contentExcerpt: 'This is an offensive post content', + image: '/some/offensive/image.jpg', + deleted: false, + }, + { + author: troll, + categoryIds, + }, + ), + Factory.build( + 'comment', + { + id: 'c1', + content: 'Disabled comment', + contentExcerpt: 'Disabled comment', + }, + { + author: troll, + postId: 'p3', + }, + ), ]) const { server } = createServer({ @@ -105,9 +134,9 @@ beforeAll(async () => { const trollingComment = resources[2] const reports = await Promise.all([ - factory.create('Report'), - factory.create('Report'), - factory.create('Report'), + Factory.build('report'), + Factory.build('report'), + Factory.build('report'), ]) const reportAgainstTroll = reports[0] const reportAgainstTrollingPost = reports[1] @@ -154,7 +183,7 @@ beforeAll(async () => { }) afterAll(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('softDeleteMiddleware', () => { diff --git a/backend/src/middleware/validation/validationMiddleware.spec.js b/backend/src/middleware/validation/validationMiddleware.spec.js index 38cd010b4..b2c669369 100644 --- a/backend/src/middleware/validation/validationMiddleware.spec.js +++ b/backend/src/middleware/validation/validationMiddleware.spec.js @@ -1,10 +1,9 @@ import { gql } from '../../helpers/jest' -import Factory from '../../factories' +import Factory, { cleanDatabase } from '../../db/factories' import { getNeode, getDriver } from '../../db/neo4j' import { createTestClient } from 'apollo-server-testing' import createServer from '../../server' -const factory = Factory() const neode = getNeode() const driver = getDriver() let authenticatedUser, @@ -94,14 +93,14 @@ beforeAll(() => { beforeEach(async () => { users = await Promise.all([ - factory.create('User', { + Factory.build('user', { id: 'reporting-user', }), - factory.create('User', { + Factory.build('user', { id: 'moderating-user', role: 'moderator', }), - factory.create('User', { + Factory.build('user', { id: 'commenting-user', }), ]) @@ -119,20 +118,30 @@ beforeEach(async () => { moderatingUser = users[1] commentingUser = users[2] const posts = await Promise.all([ - factory.create('Post', { - id: 'offensive-post', - authorId: 'moderating-user', - }), - factory.create('Post', { - id: 'post-4-commenting', - authorId: 'commenting-user', - }), + Factory.build( + 'post', + { + id: 'offensive-post', + }, + { + authorId: 'moderating-user', + }, + ), + Factory.build( + 'post', + { + id: 'post-4-commenting', + }, + { + authorId: 'commenting-user', + }, + ), ]) offensivePost = posts[0] }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('validateCreateComment', () => { @@ -182,10 +191,15 @@ describe('validateCreateComment', () => { describe('validateUpdateComment', () => { let updateCommentVariables beforeEach(async () => { - await factory.create('Comment', { - id: 'comment-id', - authorId: 'commenting-user', - }) + await Factory.build( + 'comment', + { + id: 'comment-id', + }, + { + authorId: 'commenting-user', + }, + ) updateCommentVariables = { id: 'whatever', content: '', @@ -328,7 +342,7 @@ describe('validateReport', () => { describe('validateReview', () => { beforeEach(async () => { - const reportAgainstModerator = await factory.create('Report') + const reportAgainstModerator = await Factory.build('report') await Promise.all([ reportAgainstModerator.relateTo(reportingUser, 'filed', { ...reportVariables, @@ -370,7 +384,7 @@ describe('validateReview', () => { }) it('throws an error if a moderator tries to review their own resource(Post|Comment)', async () => { - const reportAgainstOffensivePost = await factory.create('Report') + const reportAgainstOffensivePost = await Factory.build('report') await Promise.all([ reportAgainstOffensivePost.relateTo(reportingUser, 'filed', { ...reportVariables, @@ -389,7 +403,7 @@ describe('validateReview', () => { describe('moderate a resource that is not a (Comment|Post|User) ', () => { beforeEach(async () => { - await Promise.all([factory.create('Tag', { id: 'tag-id' })]) + await Promise.all([Factory.build('tag', { id: 'tag-id' })]) }) it('returns null', async () => { @@ -419,7 +433,7 @@ describe('validateReview', () => { id: 'updating-user', name: 'John Doughnut', } - updatingUser = await factory.create('User', userParams) + updatingUser = await Factory.build('user', userParams) authenticatedUser = await updatingUser.toJson() }) diff --git a/backend/src/models/Post.js b/backend/src/models/Post.js index 154456cf1..63a36d3a2 100644 --- a/backend/src/models/Post.js +++ b/backend/src/models/Post.js @@ -52,5 +52,4 @@ export default { }, }, pinned: { type: 'boolean', default: null, valid: [null, true] }, - pinnedAt: { type: 'string', isoDate: true }, } diff --git a/backend/src/models/User.spec.js b/backend/src/models/User.spec.js index 7bdde7014..f448cbf08 100644 --- a/backend/src/models/User.spec.js +++ b/backend/src/models/User.spec.js @@ -1,11 +1,10 @@ -import Factory from '../factories' +import { cleanDatabase } from '../db/factories' import { getNeode } from '../db/neo4j' -const factory = Factory() const neode = getNeode() afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('role', () => { diff --git a/backend/src/schema/resolvers/comments.spec.js b/backend/src/schema/resolvers/comments.spec.js index 9877161db..9f633c8b0 100644 --- a/backend/src/schema/resolvers/comments.spec.js +++ b/backend/src/schema/resolvers/comments.spec.js @@ -1,4 +1,4 @@ -import Factory from '../../factories' +import Factory, { cleanDatabase } from '../../db/factories' import { gql } from '../../helpers/jest' import { createTestClient } from 'apollo-server-testing' import createServer from '../../server' @@ -6,12 +6,11 @@ import { getNeode, getDriver } from '../../db/neo4j' const driver = getDriver() const neode = getNeode() -const factory = Factory() let variables, mutate, authenticatedUser, commentAuthor, newlyCreatedComment beforeAll(async () => { - await factory.cleanDatabase() + await cleanDatabase() const { server } = createServer({ context: () => { return { @@ -33,7 +32,7 @@ beforeEach(async () => { }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) const createCommentMutation = gql` @@ -48,18 +47,28 @@ const createCommentMutation = gql` } ` const setupPostAndComment = async () => { - commentAuthor = await factory.create('User') - await factory.create('Post', { - id: 'p1', - content: 'Post to be commented', - categoryIds: ['cat9'], - }) - newlyCreatedComment = await factory.create('Comment', { - id: 'c456', - postId: 'p1', - author: commentAuthor, - content: 'Comment to be deleted', - }) + commentAuthor = await Factory.build('user') + await Factory.build( + 'post', + { + id: 'p1', + content: 'Post to be commented', + }, + { + categoryIds: ['cat9'], + }, + ) + newlyCreatedComment = await Factory.build( + 'comment', + { + id: 'c456', + content: 'Comment to be deleted', + }, + { + postId: 'p1', + author: commentAuthor, + }, + ) variables = { ...variables, id: 'c456', @@ -88,7 +97,7 @@ describe('CreateComment', () => { describe('given a post', () => { beforeEach(async () => { - await factory.create('Post', { categoryIds: ['cat9'], id: 'p1' }) + await Factory.build('post', { id: 'p1' }, { categoryIds: ['cat9'] }) variables = { ...variables, postId: 'p1', @@ -141,7 +150,7 @@ describe('UpdateComment', () => { describe('authenticated but not the author', () => { beforeEach(async () => { - const randomGuy = await factory.create('User') + const randomGuy = await Factory.build('user') authenticatedUser = await randomGuy.toJson() }) @@ -233,7 +242,7 @@ describe('DeleteComment', () => { describe('authenticated but not the author', () => { beforeEach(async () => { - const randomGuy = await factory.create('User') + const randomGuy = await Factory.build('user') authenticatedUser = await randomGuy.toJson() }) diff --git a/backend/src/schema/resolvers/donations.spec.js b/backend/src/schema/resolvers/donations.spec.js index c382eb475..ea5ee4e09 100644 --- a/backend/src/schema/resolvers/donations.spec.js +++ b/backend/src/schema/resolvers/donations.spec.js @@ -1,11 +1,10 @@ import { createTestClient } from 'apollo-server-testing' -import Factory from '../../factories' +import Factory, { cleanDatabase } from '../../db/factories' import { gql } from '../../helpers/jest' import { getNeode, getDriver } from '../../db/neo4j' import createServer from '../../server' let mutate, query, authenticatedUser, variables -const factory = Factory() const instance = getNeode() const driver = getDriver() @@ -33,7 +32,7 @@ const donationsQuery = gql` describe('donations', () => { let currentUser, newlyCreatedDonations beforeAll(async () => { - await factory.cleanDatabase() + await cleanDatabase() authenticatedUser = undefined const { server } = createServer({ context: () => { @@ -50,11 +49,11 @@ describe('donations', () => { beforeEach(async () => { variables = {} - newlyCreatedDonations = await factory.create('Donations') + newlyCreatedDonations = await Factory.build('donations') }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('query for donations', () => { @@ -68,7 +67,7 @@ describe('donations', () => { describe('authenticated', () => { beforeEach(async () => { - currentUser = await factory.create('User', { + currentUser = await Factory.build('user', { id: 'normal-user', role: 'user', }) @@ -102,7 +101,7 @@ describe('donations', () => { describe('authenticated', () => { describe('as a normal user', () => { beforeEach(async () => { - currentUser = await factory.create('User', { + currentUser = await Factory.build('user', { id: 'normal-user', role: 'user', }) @@ -121,7 +120,7 @@ describe('donations', () => { describe('as a moderator', () => { beforeEach(async () => { - currentUser = await factory.create('User', { + currentUser = await Factory.build('user', { id: 'moderator', role: 'moderator', }) @@ -140,7 +139,7 @@ describe('donations', () => { describe('as an admin', () => { beforeEach(async () => { - currentUser = await factory.create('User', { + currentUser = await Factory.build('user', { id: 'admin', role: 'admin', }) diff --git a/backend/src/schema/resolvers/emails.spec.js b/backend/src/schema/resolvers/emails.spec.js index 97a1f0c29..94e7ede31 100644 --- a/backend/src/schema/resolvers/emails.spec.js +++ b/backend/src/schema/resolvers/emails.spec.js @@ -1,10 +1,9 @@ -import Factory from '../../factories' +import Factory, { cleanDatabase } from '../../db/factories' import { gql } from '../../helpers/jest' import { getDriver, getNeode } from '../../db/neo4j' import createServer from '../../server' import { createTestClient } from 'apollo-server-testing' -const factory = Factory() const neode = getNeode() let mutate @@ -31,7 +30,7 @@ beforeAll(() => { }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('AddEmailAddress', () => { @@ -63,7 +62,7 @@ describe('AddEmailAddress', () => { describe('authenticated', () => { beforeEach(async () => { - user = await factory.create('User', { id: '567', email: 'user@example.org' }) + user = await Factory.build('user', { id: '567' }, { email: 'user@example.org' }) authenticatedUser = await user.toJson() }) @@ -110,7 +109,7 @@ describe('AddEmailAddress', () => { describe('if another `UnverifiedEmailAddress` node already exists with that email', () => { it('throws no unique constraint violation error', async () => { - await factory.create('UnverifiedEmailAddress', { + await Factory.build('unverifiedEmailAddress', { createdAt: '2019-09-24T14:00:01.565Z', email: 'new-email@example.org', }) @@ -128,7 +127,7 @@ describe('AddEmailAddress', () => { describe('but if another user owns an `EmailAddress` already with that email', () => { it('throws UserInputError because of unique constraints', async () => { - await factory.create('User', { email: 'new-email@example.org' }) + await Factory.build('user', {}, { email: 'new-email@example.org' }) await expect(mutate({ mutation, variables })).resolves.toMatchObject({ data: { AddEmailAddress: null }, errors: [{ message: 'A user account with this email already exists.' }], @@ -169,7 +168,7 @@ describe('VerifyEmailAddress', () => { describe('authenticated', () => { beforeEach(async () => { - user = await factory.create('User', { id: '567', email: 'user@example.org' }) + user = await Factory.build('user', { id: '567' }, { email: 'user@example.org' }) authenticatedUser = await user.toJson() }) @@ -185,7 +184,7 @@ describe('VerifyEmailAddress', () => { describe('given a `UnverifiedEmailAddress`', () => { let emailAddress beforeEach(async () => { - emailAddress = await factory.create('UnverifiedEmailAddress', { + emailAddress = await Factory.build('unverifiedEmailAddress', { nonce: 'abcdef', verifiedAt: null, createdAt: new Date().toISOString(), @@ -281,7 +280,7 @@ describe('VerifyEmailAddress', () => { describe('Edge case: In the meantime someone created an `EmailAddress` node with the given email', () => { beforeEach(async () => { - await factory.create('EmailAddress', { email: 'to-be-verified@example.org' }) + await Factory.build('emailAddress', { email: 'to-be-verified@example.org' }) }) it('throws UserInputError because of unique constraints', async () => { diff --git a/backend/src/schema/resolvers/follow.spec.js b/backend/src/schema/resolvers/follow.spec.js index ad836a461..953a26d65 100644 --- a/backend/src/schema/resolvers/follow.spec.js +++ b/backend/src/schema/resolvers/follow.spec.js @@ -1,10 +1,9 @@ import { createTestClient } from 'apollo-server-testing' -import Factory from '../../factories' +import Factory, { cleanDatabase } from '../../db/factories' import { getDriver, getNeode } from '../../db/neo4j' import createServer from '../../server' import { gql } from '../../helpers/jest' -const factory = Factory() const driver = getDriver() const neode = getNeode() @@ -54,7 +53,7 @@ const userQuery = gql` ` beforeAll(async () => { - await factory.cleanDatabase() + await cleanDatabase() const { server } = createServer({ context: () => ({ driver, @@ -72,29 +71,35 @@ beforeAll(async () => { }) beforeEach(async () => { - user1 = await factory - .create('User', { + user1 = await Factory.build( + 'user', + { id: 'u1', name: 'user1', + }, + { email: 'test@example.org', password: '1234', - }) - .then(user => user.toJson()) - user2 = await factory - .create('User', { + }, + ).then(user => user.toJson()) + user2 = await Factory.build( + 'user', + { id: 'u2', name: 'user2', + }, + { email: 'test2@example.org', password: '1234', - }) - .then(user => user.toJson()) + }, + ).then(user => user.toJson()) authenticatedUser = user1 variables = { id: user2.id } }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('follow', () => { diff --git a/backend/src/schema/resolvers/locations.spec.js b/backend/src/schema/resolvers/locations.spec.js index aba11f9bc..a2929f65a 100644 --- a/backend/src/schema/resolvers/locations.spec.js +++ b/backend/src/schema/resolvers/locations.spec.js @@ -1,11 +1,9 @@ -import Factory from '../../factories' +import Factory, { cleanDatabase } from '../../db/factories' import { gql } from '../../helpers/jest' import { getNeode, getDriver } from '../../db/neo4j' import createServer from '../../server' import { createTestClient } from 'apollo-server-testing' -const factory = Factory() - let mutate, authenticatedUser const driver = getDriver() @@ -25,7 +23,7 @@ beforeAll(() => { }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('resolvers', () => { @@ -49,7 +47,7 @@ describe('resolvers', () => { id: 'u47', name: 'John Doughnut', } - const Paris = await factory.create('Location', { + const Paris = await Factory.build('location', { id: 'region.9397217726497330', name: 'Paris', type: 'region', @@ -58,7 +56,7 @@ describe('resolvers', () => { nameEN: 'Paris', }) - const user = await factory.create('User', { + const user = await Factory.build('user', { id: 'u47', name: 'John Doe', }) diff --git a/backend/src/schema/resolvers/moderation.spec.js b/backend/src/schema/resolvers/moderation.spec.js index cd502be75..b62d35ee8 100644 --- a/backend/src/schema/resolvers/moderation.spec.js +++ b/backend/src/schema/resolvers/moderation.spec.js @@ -1,10 +1,9 @@ import { createTestClient } from 'apollo-server-testing' -import Factory from '../../factories' +import Factory, { cleanDatabase } from '../../db/factories' import { gql } from '../../helpers/jest' import { getNeode, getDriver } from '../../db/neo4j' import createServer from '../../server' -const factory = Factory() const neode = getNeode() const driver = getDriver() @@ -54,7 +53,7 @@ const reviewMutation = gql` describe('moderate resources', () => { beforeAll(async () => { - await factory.cleanDatabase() + await cleanDatabase() authenticatedUser = undefined const { server } = createServer({ context: () => { @@ -80,23 +79,33 @@ describe('moderate resources', () => { closed: false, } authenticatedUser = null - moderator = await factory.create('User', { - id: 'moderator-id', - name: 'Moderator', - email: 'moderator@example.org', - password: '1234', - role: 'moderator', - }) - nonModerator = await factory.create('User', { - id: 'non-moderator', - name: 'Non Moderator', - email: 'non.moderator@example.org', - password: '1234', - }) + moderator = await Factory.build( + 'user', + { + id: 'moderator-id', + name: 'Moderator', + role: 'moderator', + }, + { + email: 'moderator@example.org', + password: '1234', + }, + ) + nonModerator = await Factory.build( + 'user', + { + id: 'non-moderator', + name: 'Non Moderator', + }, + { + email: 'non.moderator@example.org', + password: '1234', + }, + ) }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('review to close report, leaving resource enabled', () => { @@ -127,10 +136,10 @@ describe('moderate resources', () => { describe('moderator', () => { beforeEach(async () => { authenticatedUser = await moderator.toJson() - const questionablePost = await factory.create('Post', { + const questionablePost = await Factory.build('post', { id: 'should-i-be-disabled', }) - const reportAgainstQuestionablePost = await factory.create('Report') + const reportAgainstQuestionablePost = await Factory.build('report') await Promise.all([ reportAgainstQuestionablePost.relateTo(nonModerator, 'filed', { resourceId: 'should-i-be-disabled', @@ -229,10 +238,10 @@ describe('moderate resources', () => { describe('moderate a comment', () => { beforeEach(async () => { - const trollingComment = await factory.create('Comment', { + const trollingComment = await Factory.build('comment', { id: 'comment-id', }) - const reportAgainstTrollingComment = await factory.create('Report') + const reportAgainstTrollingComment = await Factory.build('report') await Promise.all([ reportAgainstTrollingComment.relateTo(nonModerator, 'filed', { resourceId: 'comment-id', @@ -307,10 +316,10 @@ describe('moderate resources', () => { describe('moderate a post', () => { beforeEach(async () => { - const trollingPost = await factory.create('Post', { + const trollingPost = await Factory.build('post', { id: 'post-id', }) - const reportAgainstTrollingPost = await factory.create('Report') + const reportAgainstTrollingPost = await Factory.build('report') await Promise.all([ reportAgainstTrollingPost.relateTo(nonModerator, 'filed', { resourceId: 'post-id', @@ -387,10 +396,10 @@ describe('moderate resources', () => { describe('moderate a user', () => { beforeEach(async () => { - const troll = await factory.create('User', { + const troll = await Factory.build('user', { id: 'user-id', }) - const reportAgainstTroll = await factory.create('Report') + const reportAgainstTroll = await Factory.build('report') await Promise.all([ reportAgainstTroll.relateTo(nonModerator, 'filed', { resourceId: 'user-id', @@ -504,10 +513,10 @@ describe('moderate resources', () => { describe('moderate a comment', () => { beforeEach(async () => { - const trollingComment = await factory.create('Comment', { + const trollingComment = await Factory.build('comment', { id: 'comment-id', }) - const reportAgainstTrollingComment = await factory.create('Report') + const reportAgainstTrollingComment = await Factory.build('report') await Promise.all([ reportAgainstTrollingComment.relateTo(nonModerator, 'filed', { resourceId: 'comment-id', @@ -568,10 +577,10 @@ describe('moderate resources', () => { describe('moderate a post', () => { beforeEach(async () => { - const trollingPost = await factory.create('Post', { + const trollingPost = await Factory.build('post', { id: 'post-id', }) - const reportAgainstTrollingPost = await factory.create('Report') + const reportAgainstTrollingPost = await Factory.build('report') await Promise.all([ reportAgainstTrollingPost.relateTo(nonModerator, 'filed', { resourceId: 'post-id', @@ -633,10 +642,10 @@ describe('moderate resources', () => { describe('moderate a user', () => { beforeEach(async () => { - const troll = await factory.create('User', { + const troll = await Factory.build('user', { id: 'user-id', }) - const reportAgainstTroll = await factory.create('Report') + const reportAgainstTroll = await Factory.build('report') await Promise.all([ reportAgainstTroll.relateTo(nonModerator, 'filed', { resourceId: 'user-id', diff --git a/backend/src/schema/resolvers/notifications.spec.js b/backend/src/schema/resolvers/notifications.spec.js index a5c46e930..9d7795dd4 100644 --- a/backend/src/schema/resolvers/notifications.spec.js +++ b/backend/src/schema/resolvers/notifications.spec.js @@ -1,10 +1,9 @@ -import Factory from '../../factories' +import Factory, { cleanDatabase } from '../../db/factories' import { gql } from '../../helpers/jest' import { getDriver } from '../../db/neo4j' import { createTestClient } from 'apollo-server-testing' import createServer from '../.././server' -const factory = Factory() const driver = getDriver() let authenticatedUser let user @@ -32,52 +31,77 @@ beforeEach(async () => { }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('given some notifications', () => { beforeEach(async () => { const categoryIds = ['cat1'] - author = await factory.create('User', { id: 'author' }) - user = await factory.create('User', { id: 'you' }) + author = await Factory.build('user', { id: 'author' }) + user = await Factory.build('user', { id: 'you' }) const [neighbor] = await Promise.all([ - factory.create('User', { id: 'neighbor' }), - factory.create('Category', { id: 'cat1' }), + Factory.build('user', { id: 'neighbor' }), + Factory.build('category', { id: 'cat1' }), ]) const [post1, post2, post3] = await Promise.all([ - factory.create('Post', { author, id: 'p1', categoryIds, content: 'Not for you' }), - factory.create('Post', { - author, - id: 'p2', - categoryIds, - content: 'Already seen post mention', - }), - factory.create('Post', { - author, - id: 'p3', - categoryIds, - content: 'You have been mentioned in a post', - }), + Factory.build('post', { id: 'p1', content: 'Not for you' }, { author, categoryIds }), + Factory.build( + 'post', + { + id: 'p2', + content: 'Already seen post mention', + }, + { + author, + categoryIds, + }, + ), + Factory.build( + 'post', + { + id: 'p3', + content: 'You have been mentioned in a post', + }, + { + author, + categoryIds, + }, + ), ]) const [comment1, comment2, comment3] = await Promise.all([ - factory.create('Comment', { - author, - postId: 'p3', - id: 'c1', - content: 'You have seen this comment mentioning already', - }), - factory.create('Comment', { - author, - postId: 'p3', - id: 'c2', - content: 'You have been mentioned in a comment', - }), - factory.create('Comment', { - author, - postId: 'p3', - id: 'c3', - content: 'Somebody else was mentioned in a comment', - }), + Factory.build( + 'comment', + { + id: 'c1', + content: 'You have seen this comment mentioning already', + }, + { + author, + postId: 'p3', + }, + ), + Factory.build( + 'comment', + { + id: 'c2', + content: 'You have been mentioned in a comment', + }, + { + author, + postId: 'p3', + }, + ), + Factory.build( + 'comment', + { + id: 'c3', + content: 'Somebody else was mentioned in a comment', + }, + { + author, + postId: 'p3', + }, + ), ]) await Promise.all([ post1.relateTo(neighbor, 'notified', { diff --git a/backend/src/schema/resolvers/passwordReset.spec.js b/backend/src/schema/resolvers/passwordReset.spec.js index d7b3a0157..b48498ee7 100644 --- a/backend/src/schema/resolvers/passwordReset.spec.js +++ b/backend/src/schema/resolvers/passwordReset.spec.js @@ -1,4 +1,4 @@ -import Factory from '../../factories' +import Factory, { cleanDatabase } from '../../db/factories' import { gql } from '../../helpers/jest' import { getNeode, getDriver } from '../../db/neo4j' import createPasswordReset from './helpers/createPasswordReset' @@ -7,7 +7,6 @@ import { createTestClient } from 'apollo-server-testing' const neode = getNeode() const driver = getDriver() -const factory = Factory() let mutate let authenticatedUser @@ -39,15 +38,19 @@ beforeAll(() => { }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('passwordReset', () => { describe('given a user', () => { beforeEach(async () => { - await factory.create('User', { - email: 'user@example.org', - }) + await Factory.build( + 'user', + {}, + { + email: 'user@example.org', + }, + ) }) describe('requestPasswordReset', () => { @@ -123,11 +126,16 @@ describe('resetPassword', () => { describe('given a user', () => { beforeEach(async () => { - await factory.create('User', { - email: 'user@example.org', - role: 'user', - password: '1234', - }) + await Factory.build( + 'user', + { + role: 'user', + }, + { + email: 'user@example.org', + password: '1234', + }, + ) }) describe('invalid email', () => { diff --git a/backend/src/schema/resolvers/posts.spec.js b/backend/src/schema/resolvers/posts.spec.js index 56a47afa7..88a09843d 100644 --- a/backend/src/schema/resolvers/posts.spec.js +++ b/backend/src/schema/resolvers/posts.spec.js @@ -1,11 +1,10 @@ import { createTestClient } from 'apollo-server-testing' -import Factory from '../../factories' +import Factory, { cleanDatabase } from '../../db/factories' import { gql } from '../../helpers/jest' import { getNeode, getDriver } from '../../db/neo4j' import createServer from '../../server' const driver = getDriver() -const factory = Factory() const neode = getNeode() let query @@ -40,7 +39,7 @@ const createPostMutation = gql` ` beforeAll(async () => { - await factory.cleanDatabase() + await cleanDatabase() const { server } = createServer({ context: () => { return { @@ -56,12 +55,17 @@ beforeAll(async () => { beforeEach(async () => { variables = {} - user = await factory.create('User', { - id: 'current-user', - name: 'TestUser', - email: 'test@example.org', - password: '1234', - }) + user = await Factory.build( + 'user', + { + id: 'current-user', + name: 'TestUser', + }, + { + email: 'test@example.org', + password: '1234', + }, + ) await Promise.all([ neode.create('Category', { id: 'cat9', @@ -88,7 +92,7 @@ beforeEach(async () => { }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('Post', () => { @@ -96,21 +100,31 @@ describe('Post', () => { let followedUser, happyPost, cryPost beforeEach(async () => { ;[followedUser] = await Promise.all([ - factory.create('User', { - id: 'followed-by-me', - email: 'followed@example.org', - name: 'Followed User', - password: '1234', - }), + Factory.build( + 'user', + { + id: 'followed-by-me', + name: 'Followed User', + }, + { + email: 'followed@example.org', + password: '1234', + }, + ), ]) ;[happyPost, cryPost] = await Promise.all([ - factory.create('Post', { id: 'happy-post', categoryIds: ['cat4'] }), - factory.create('Post', { id: 'cry-post', categoryIds: ['cat15'] }), - factory.create('Post', { - id: 'post-by-followed-user', - categoryIds: ['cat9'], - author: followedUser, - }), + Factory.build('post', { id: 'happy-post' }, { categoryIds: ['cat4'] }), + Factory.build('post', { id: 'cry-post' }, { categoryIds: ['cat15'] }), + Factory.build( + 'post', + { + id: 'post-by-followed-user', + }, + { + categoryIds: ['cat9'], + author: followedUser, + }, + ), ]) }) @@ -340,14 +354,19 @@ describe('UpdatePost', () => { } ` beforeEach(async () => { - author = await factory.create('User', { slug: 'the-author' }) - newlyCreatedPost = await factory.create('Post', { - author, - id: 'p9876', - title: 'Old title', - content: 'Old content', - categoryIds, - }) + author = await Factory.build('user', { slug: 'the-author' }) + newlyCreatedPost = await Factory.build( + 'post', + { + id: 'p9876', + title: 'Old title', + content: 'Old content', + }, + { + author, + categoryIds, + }, + ) variables = { id: 'p9876', @@ -529,10 +548,15 @@ describe('UpdatePost', () => { describe('are allowed to pin posts', () => { beforeEach(async () => { - await factory.create('Post', { - id: 'created-and-pinned-by-same-admin', - author: admin, - }) + await Factory.build( + 'post', + { + id: 'created-and-pinned-by-same-admin', + }, + { + author: admin, + }, + ) variables = { ...variables, id: 'created-and-pinned-by-same-admin' } }) @@ -589,15 +613,20 @@ describe('UpdatePost', () => { describe('post created by another admin', () => { let otherAdmin beforeEach(async () => { - otherAdmin = await factory.create('User', { + otherAdmin = await Factory.build('user', { role: 'admin', name: 'otherAdmin', }) authenticatedUser = await otherAdmin.toJson() - await factory.create('Post', { - id: 'created-by-one-admin-pinned-by-different-one', - author: otherAdmin, - }) + await Factory.build( + 'post', + { + id: 'created-by-one-admin-pinned-by-different-one', + }, + { + author: otherAdmin, + }, + ) }) it('responds with the updated Post', async () => { @@ -654,10 +683,15 @@ describe('UpdatePost', () => { describe('pinned post already exists', () => { let pinnedPost beforeEach(async () => { - await factory.create('Post', { - id: 'only-pinned-post', - author: admin, - }) + await Factory.build( + 'post', + { + id: 'only-pinned-post', + }, + { + author: admin, + }, + ) await mutate({ mutation: pinPostMutation, variables }) }) @@ -683,12 +717,12 @@ describe('UpdatePost', () => { describe('PostOrdering', () => { beforeEach(async () => { - await factory.create('Post', { + await Factory.build('post', { id: 'im-a-pinned-post', createdAt: '2019-11-22T17:26:29.070Z', pinned: true, }) - await factory.create('Post', { + await Factory.build('post', { id: 'i-was-created-before-pinned-post', // fairly old, so this should be 3rd createdAt: '2019-10-22T17:26:29.070Z', @@ -807,7 +841,7 @@ describe('UpdatePost', () => { describe('admin can unpin posts', () => { let admin, pinnedPost beforeEach(async () => { - pinnedPost = await factory.create('Post', { id: 'post-to-be-unpinned' }) + pinnedPost = await Factory.build('post', { id: 'post-to-be-unpinned' }) admin = await user.update({ role: 'admin', name: 'Admin', @@ -874,15 +908,20 @@ describe('DeletePost', () => { ` beforeEach(async () => { - author = await factory.create('User') - await factory.create('Post', { - id: 'p4711', - author, - title: 'I will be deleted', - content: 'To be deleted', - image: 'path/to/some/image', - categoryIds, - }) + author = await Factory.build('user') + await Factory.build( + 'post', + { + id: 'p4711', + title: 'I will be deleted', + content: 'To be deleted', + image: 'path/to/some/image', + }, + { + author, + categoryIds, + }, + ) variables = { ...variables, id: 'p4711' } }) @@ -929,11 +968,16 @@ describe('DeletePost', () => { describe('if there are comments on the post', () => { beforeEach(async () => { - await factory.create('Comment', { - postId: 'p4711', - content: 'to be deleted comment content', - contentExcerpt: 'to be deleted comment content', - }) + await Factory.build( + 'comment', + { + content: 'to be deleted comment content', + contentExcerpt: 'to be deleted comment content', + }, + { + postId: 'p4711', + }, + ) }) it('marks the comments as deleted', async () => { @@ -988,11 +1032,16 @@ describe('emotions', () => { beforeEach(async () => { author = await neode.create('User', { id: 'u257' }) - postToEmote = await factory.create('Post', { - author, - id: 'p1376', - categoryIds, - }) + postToEmote = await Factory.build( + 'post', + { + id: 'p1376', + }, + { + author, + categoryIds, + }, + ) variables = { ...variables, diff --git a/backend/src/schema/resolvers/registration.spec.js b/backend/src/schema/resolvers/registration.spec.js index 23b1f9d2a..63dc35519 100644 --- a/backend/src/schema/resolvers/registration.spec.js +++ b/backend/src/schema/resolvers/registration.spec.js @@ -1,10 +1,9 @@ -import Factory from '../../factories' +import Factory, { cleanDatabase } from '../../db/factories' import { gql } from '../../helpers/jest' import { getDriver, getNeode } from '../../db/neo4j' import createServer from '../../server' import { createTestClient } from 'apollo-server-testing' -const factory = Factory() const neode = getNeode() let mutate @@ -30,7 +29,7 @@ beforeAll(() => { }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('Signup', () => { @@ -58,11 +57,16 @@ describe('Signup', () => { describe('as admin', () => { beforeEach(async () => { - const admin = await factory.create('User', { - role: 'admin', - email: 'admin@example.org', - password: '1234', - }) + const admin = await Factory.build( + 'user', + { + role: 'admin', + }, + { + email: 'admin@example.org', + password: '1234', + }, + ) authenticatedUser = await admin.toJson() }) @@ -90,9 +94,9 @@ describe('Signup', () => { }) describe('if the email already exists', () => { - let email + let emailAddress beforeEach(async () => { - email = await factory.create('EmailAddress', { + emailAddress = await Factory.build('emailAddress', { email: 'someuser@example.org', verifiedAt: null, }) @@ -100,7 +104,8 @@ describe('Signup', () => { describe('and the user has registered already', () => { beforeEach(async () => { - await factory.create('User', { email }) + const user = await Factory.build('userWithoutEmailAddress') + await emailAddress.relateTo(user, 'belongsTo') }) it('throws UserInputError error because of unique constraint violation', async () => { diff --git a/backend/src/schema/resolvers/reports.spec.js b/backend/src/schema/resolvers/reports.spec.js index 7f827b111..0e690c19e 100644 --- a/backend/src/schema/resolvers/reports.spec.js +++ b/backend/src/schema/resolvers/reports.spec.js @@ -1,10 +1,9 @@ import { createTestClient } from 'apollo-server-testing' import createServer from '../.././server' -import Factory from '../../factories' +import Factory, { cleanDatabase } from '../../db/factories' import { gql } from '../../helpers/jest' import { getDriver, getNeode } from '../../db/neo4j' -const factory = Factory() const instance = getNeode() const driver = getDriver() @@ -53,7 +52,7 @@ describe('file a report on a resource', () => { } beforeAll(async () => { - await factory.cleanDatabase() + await cleanDatabase() const { server } = createServer({ context: () => { return { @@ -68,7 +67,7 @@ describe('file a report on a resource', () => { }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('report a resource', () => { @@ -84,24 +83,39 @@ describe('file a report on a resource', () => { describe('authenticated', () => { beforeEach(async () => { - currentUser = await factory.create('User', { - id: 'current-user-id', - role: 'user', - email: 'test@example.org', - password: '1234', - }) - otherReportingUser = await factory.create('User', { - id: 'other-reporting-user-id', - role: 'user', - email: 'reporting@example.org', - password: '1234', - }) - await factory.create('User', { - id: 'abusive-user-id', - role: 'user', - name: 'abusive-user', - email: 'abusive-user@example.org', - }) + currentUser = await Factory.build( + 'user', + { + id: 'current-user-id', + role: 'user', + }, + { + email: 'test@example.org', + password: '1234', + }, + ) + otherReportingUser = await Factory.build( + 'user', + { + id: 'other-reporting-user-id', + role: 'user', + }, + { + email: 'reporting@example.org', + password: '1234', + }, + ) + await Factory.build( + 'user', + { + id: 'abusive-user-id', + role: 'user', + name: 'abusive-user', + }, + { + email: 'abusive-user@example.org', + }, + ) await instance.create('Category', { id: 'cat9', name: 'Democracy & Politics', @@ -341,12 +355,17 @@ describe('file a report on a resource', () => { describe('reported resource is a post', () => { beforeEach(async () => { - await factory.create('Post', { - author: currentUser, - id: 'post-to-report-id', - title: 'This is a post that is going to be reported', - categoryIds, - }) + await Factory.build( + 'post', + { + id: 'post-to-report-id', + title: 'This is a post that is going to be reported', + }, + { + author: currentUser, + categoryIds, + }, + ) }) it('returns type "Post"', async () => { @@ -394,21 +413,30 @@ describe('file a report on a resource', () => { }) describe('reported resource is a comment', () => { - let createPostVariables beforeEach(async () => { - createPostVariables = { - id: 'p1', - title: 'post to comment on', - content: 'please comment on me', - categoryIds, - } - await factory.create('Post', { ...createPostVariables, author: currentUser }) - await factory.create('Comment', { - author: currentUser, - postId: 'p1', - id: 'comment-to-report-id', - content: 'Post comment to be reported.', - }) + await Factory.build( + 'post', + { + id: 'p1', + title: 'post to comment on', + content: 'please comment on me', + }, + { + categoryIds, + author: currentUser, + }, + ) + await Factory.build( + 'comment', + { + id: 'comment-to-report-id', + content: 'Post comment to be reported.', + }, + { + author: currentUser, + postId: 'p1', + }, + ) }) it('returns type "Comment"', async () => { @@ -457,7 +485,7 @@ describe('file a report on a resource', () => { describe('reported resource is a tag', () => { beforeEach(async () => { - await factory.create('Tag', { + await Factory.build('tag', { id: 'tag-to-report-id', }) }) @@ -515,24 +543,39 @@ describe('file a report on a resource', () => { beforeEach(async () => { authenticatedUser = null - moderator = await factory.create('User', { - id: 'moderator-1', - role: 'moderator', - email: 'moderator@example.org', - password: '1234', - }) - currentUser = await factory.create('User', { - id: 'current-user-id', - role: 'user', - email: 'current.user@example.org', - password: '1234', - }) - abusiveUser = await factory.create('User', { - id: 'abusive-user-1', - role: 'user', - name: 'abusive-user', - email: 'abusive-user@example.org', - }) + moderator = await Factory.build( + 'user', + { + id: 'moderator-1', + role: 'moderator', + }, + { + email: 'moderator@example.org', + password: '1234', + }, + ) + currentUser = await Factory.build( + 'user', + { + id: 'current-user-id', + role: 'user', + }, + { + email: 'current.user@example.org', + password: '1234', + }, + ) + abusiveUser = await Factory.build( + 'user', + { + id: 'abusive-user-1', + role: 'user', + name: 'abusive-user', + }, + { + email: 'abusive-user@example.org', + }, + ) await instance.create('Category', { id: 'cat9', name: 'Democracy & Politics', @@ -540,31 +583,51 @@ describe('file a report on a resource', () => { }) await Promise.all([ - factory.create('Post', { - author: abusiveUser, - id: 'abusive-post-1', - categoryIds, - content: 'Interesting Knowledge', - }), - factory.create('Post', { - author: moderator, - id: 'post-2', - categoryIds, - content: 'More things to do …', - }), - factory.create('Post', { - author: currentUser, - id: 'post-3', - categoryIds, - content: 'I am at school …', - }), + Factory.build( + 'post', + { + id: 'abusive-post-1', + content: 'Interesting Knowledge', + }, + { + categoryIds, + author: abusiveUser, + }, + ), + Factory.build( + 'post', + { + id: 'post-2', + content: 'More things to do …', + }, + { + author: moderator, + categoryIds, + }, + ), + Factory.build( + 'post', + { + id: 'post-3', + content: 'I am at school …', + }, + { + categoryIds, + author: currentUser, + }, + ), ]) await Promise.all([ - factory.create('Comment', { - author: currentUser, - id: 'abusive-comment-1', - postId: 'post-1', - }), + Factory.build( + 'comment', + { + id: 'abusive-comment-1', + }, + { + postId: 'post-2', + author: currentUser, + }, + ), ]) authenticatedUser = await currentUser.toJson() await Promise.all([ diff --git a/backend/src/schema/resolvers/rewards.spec.js b/backend/src/schema/resolvers/rewards.spec.js index fe2807f25..a20472243 100644 --- a/backend/src/schema/resolvers/rewards.spec.js +++ b/backend/src/schema/resolvers/rewards.spec.js @@ -1,10 +1,9 @@ import { createTestClient } from 'apollo-server-testing' -import Factory from '../../factories' +import Factory, { cleanDatabase } from '../../db/factories' import { gql } from '../../helpers/jest' import { getNeode, getDriver } from '../../db/neo4j' import createServer from '../../server' -const factory = Factory() const driver = getDriver() const instance = getNeode() @@ -31,23 +30,38 @@ describe('rewards', () => { }) beforeEach(async () => { - regularUser = await factory.create('User', { - id: 'regular-user-id', - role: 'user', - email: 'user@example.org', - password: '1234', - }) - moderator = await factory.create('User', { - id: 'moderator-id', - role: 'moderator', - email: 'moderator@example.org', - }) - administrator = await factory.create('User', { - id: 'admin-id', - role: 'admin', - email: 'admin@example.org', - }) - badge = await factory.create('Badge', { + regularUser = await Factory.build( + 'user', + { + id: 'regular-user-id', + role: 'user', + }, + { + email: 'user@example.org', + password: '1234', + }, + ) + moderator = await Factory.build( + 'user', + { + id: 'moderator-id', + role: 'moderator', + }, + { + email: 'moderator@example.org', + }, + ) + administrator = await Factory.build( + 'user', + { + id: 'admin-id', + role: 'admin', + }, + { + email: 'admin@example.org', + }, + ) + badge = await Factory.build('badge', { id: 'indiegogo_en_rhino', type: 'crowdfunding', status: 'permanent', @@ -56,7 +70,7 @@ describe('rewards', () => { }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('reward', () => { @@ -130,7 +144,7 @@ describe('rewards', () => { }) it('rewards a second different badge to same user', async () => { - await factory.create('Badge', { + await Factory.build('badge', { id: 'indiegogo_en_racoon', icon: '/img/badges/indiegogo_en_racoon.svg', }) @@ -172,10 +186,15 @@ describe('rewards', () => { }, errors: undefined, } - await factory.create('User', { - id: 'regular-user-2-id', - email: 'regular2@email.com', - }) + await Factory.build( + 'user', + { + id: 'regular-user-2-id', + }, + { + email: 'regular2@email.com', + }, + ) await mutate({ mutation: rewardMutation, variables, diff --git a/backend/src/schema/resolvers/shout.spec.js b/backend/src/schema/resolvers/shout.spec.js index 104a28399..f5ec8f5fd 100644 --- a/backend/src/schema/resolvers/shout.spec.js +++ b/backend/src/schema/resolvers/shout.spec.js @@ -1,11 +1,10 @@ import { createTestClient } from 'apollo-server-testing' -import Factory from '../../factories' +import Factory, { cleanDatabase } from '../../db/factories' import { gql } from '../../helpers/jest' import { getNeode, getDriver } from '../../db/neo4j' import createServer from '../../server' let mutate, query, authenticatedUser, variables -const factory = Factory() const instance = getNeode() const driver = getDriver() @@ -47,22 +46,32 @@ describe('shout and unshout posts', () => { query = createTestClient(server).query }) beforeEach(async () => { - currentUser = await factory.create('User', { - id: 'current-user-id', - name: 'Current User', - email: 'current.user@example.org', - password: '1234', - }) + currentUser = await Factory.build( + 'user', + { + id: 'current-user-id', + name: 'Current User', + }, + { + email: 'current.user@example.org', + password: '1234', + }, + ) - postAuthor = await factory.create('User', { - id: 'id-of-another-user', - name: 'Another User', - email: 'another.user@example.org', - password: '1234', - }) + postAuthor = await Factory.build( + 'user', + { + id: 'id-of-another-user', + name: 'Another User', + }, + { + email: 'another.user@example.org', + password: '1234', + }, + ) }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('shout', () => { @@ -78,16 +87,26 @@ describe('shout and unshout posts', () => { describe('authenticated', () => { beforeEach(async () => { authenticatedUser = await currentUser.toJson() - await factory.create('Post', { - name: 'Other user post', - id: 'another-user-post-id', - author: postAuthor, - }) - await factory.create('Post', { - name: 'current user post', - id: 'current-user-post-id', - author: currentUser, - }) + await Factory.build( + 'post', + { + name: 'Other user post', + id: 'another-user-post-id', + }, + { + author: postAuthor, + }, + ) + await Factory.build( + 'post', + { + name: 'current user post', + id: 'current-user-post-id', + }, + { + author: currentUser, + }, + ) variables = {} }) @@ -144,11 +163,16 @@ describe('shout and unshout posts', () => { describe('authenticated', () => { beforeEach(async () => { authenticatedUser = await currentUser.toJson() - await factory.create('Post', { - name: 'Posted By Another User', - id: 'posted-by-another-user', - author: postAuthor, - }) + await Factory.build( + 'post', + { + name: 'Posted By Another User', + id: 'posted-by-another-user', + }, + { + author: postAuthor, + }, + ) await mutate({ mutation: mutationShoutPost, variables: { id: 'posted-by-another-user' }, diff --git a/backend/src/schema/resolvers/socialMedia.spec.js b/backend/src/schema/resolvers/socialMedia.spec.js index f292b58a0..898174199 100644 --- a/backend/src/schema/resolvers/socialMedia.spec.js +++ b/backend/src/schema/resolvers/socialMedia.spec.js @@ -1,41 +1,46 @@ import { createTestClient } from 'apollo-server-testing' import createServer from '../../server' -import Factory from '../../factories' +import Factory, { cleanDatabase } from '../../db/factories' import { gql } from '../../helpers/jest' -import { getNeode, getDriver } from '../../db/neo4j' +import { getDriver } from '../../db/neo4j' const driver = getDriver() -const factory = Factory() -const neode = getNeode() describe('SocialMedia', () => { let socialMediaAction, someUser, ownerNode, owner - const ownerParams = { - email: 'pippi@example.com', - password: '1234', - name: 'Pippi Langstrumpf', - } - - const userParams = { - email: 'kalle@example.com', - password: 'abcd', - name: 'Kalle Blomqvist', - } - const url = 'https://twitter.com/pippi-langstrumpf' const newUrl = 'https://twitter.com/bullerby' const setUpSocialMedia = async () => { - const socialMediaNode = await neode.create('SocialMedia', { url }) + const socialMediaNode = await Factory.build('socialMedia', { url }) await socialMediaNode.relateTo(ownerNode, 'ownedBy') return socialMediaNode.toJson() } beforeEach(async () => { - const someUserNode = await neode.create('User', userParams) + const someUserNode = await Factory.build( + 'user', + { + name: 'Kalle Blomqvist', + }, + { + email: 'kalle@example.com', + password: 'abcd', + }, + ) + someUser = await someUserNode.toJson() - ownerNode = await neode.create('User', ownerParams) + ownerNode = await Factory.build( + 'user', + { + name: 'Pippi Langstrumpf', + }, + { + email: 'pippi@example.com', + password: '1234', + }, + ) owner = await ownerNode.toJson() socialMediaAction = async (user, mutation, variables) => { @@ -57,7 +62,7 @@ describe('SocialMedia', () => { }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('create social media', () => { diff --git a/backend/src/schema/resolvers/statistics.spec.js b/backend/src/schema/resolvers/statistics.spec.js index e2b9dafe4..c5bb5f88b 100644 --- a/backend/src/schema/resolvers/statistics.spec.js +++ b/backend/src/schema/resolvers/statistics.spec.js @@ -1,11 +1,10 @@ import { createTestClient } from 'apollo-server-testing' -import Factory from '../../factories' +import Factory, { cleanDatabase } from '../../db/factories' import { gql } from '../../helpers/jest' import { getNeode, getDriver } from '../../db/neo4j' import createServer from '../../server' let query, authenticatedUser -const factory = Factory() const instance = getNeode() const driver = getDriver() @@ -37,7 +36,7 @@ beforeAll(() => { }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('statistics', () => { @@ -45,7 +44,7 @@ describe('statistics', () => { beforeEach(async () => { await Promise.all( [...Array(6).keys()].map(() => { - return factory.create('User') + return Factory.build('user') }), ) }) @@ -62,7 +61,7 @@ describe('statistics', () => { beforeEach(async () => { await Promise.all( [...Array(3).keys()].map(() => { - return factory.create('Post') + return Factory.build('post') }), ) }) @@ -79,7 +78,7 @@ describe('statistics', () => { beforeEach(async () => { await Promise.all( [...Array(2).keys()].map(() => { - return factory.create('Comment') + return Factory.build('comment') }), ) }) @@ -97,7 +96,7 @@ describe('statistics', () => { beforeEach(async () => { users = await Promise.all( [...Array(2).keys()].map(() => { - return factory.create('User') + return Factory.build('user') }), ) await users[0].relateTo(users[1], 'following') @@ -116,12 +115,12 @@ describe('statistics', () => { beforeEach(async () => { users = await Promise.all( [...Array(2).keys()].map(() => { - return factory.create('User') + return Factory.build('user') }), ) posts = await Promise.all( [...Array(3).keys()].map(() => { - return factory.create('Post') + return Factory.build('post') }), ) await Promise.all([ diff --git a/backend/src/schema/resolvers/user_management.spec.js b/backend/src/schema/resolvers/user_management.spec.js index 5e7043e74..b343c8a1b 100644 --- a/backend/src/schema/resolvers/user_management.spec.js +++ b/backend/src/schema/resolvers/user_management.spec.js @@ -1,20 +1,19 @@ import jwt from 'jsonwebtoken' import CONFIG from './../../config' -import Factory from '../../factories' +import Factory, { cleanDatabase } from '../../db/factories' import { gql } from '../../helpers/jest' import { createTestClient } from 'apollo-server-testing' import createServer, { context } from '../../server' import encode from '../../jwt/encode' import { getNeode } from '../../db/neo4j' -const factory = Factory() const neode = getNeode() let query, mutate, variables, req, user const disable = async id => { - const moderator = await factory.create('User', { id: 'u2', role: 'moderator' }) + const moderator = await Factory.build('user', { id: 'u2', role: 'moderator' }) const user = await neode.find('User', id) - const reportAgainstUser = await factory.create('Report') + const reportAgainstUser = await Factory.build('report') await Promise.all([ reportAgainstUser.relateTo(moderator, 'filed', { resourceId: id, @@ -48,7 +47,7 @@ beforeAll(() => { }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('isLoggedIn', () => { @@ -69,7 +68,7 @@ describe('isLoggedIn', () => { describe('authenticated', () => { beforeEach(async () => { - user = await factory.create('User', { id: 'u3' }) + user = await Factory.build('user', { id: 'u3' }) const userBearerToken = encode({ id: 'u3' }) req = { headers: { authorization: `Bearer ${userBearerToken}` } } }) @@ -127,15 +126,20 @@ describe('currentUser', () => { describe('authenticated', () => { describe('and corresponding user in the database', () => { beforeEach(async () => { - await factory.create('User', { - id: 'u3', - // the `id` is the only thing that has to match the decoded JWT bearer token - avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/jimmuirhead/128.jpg', - email: 'test@example.org', - name: 'Matilde Hermiston', - slug: 'matilde-hermiston', - role: 'user', - }) + await Factory.build( + 'user', + { + id: 'u3', + // the `id` is the only thing that has to match the decoded JWT bearer token + avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/jimmuirhead/128.jpg', + name: 'Matilde Hermiston', + slug: 'matilde-hermiston', + role: 'user', + }, + { + email: 'test@example.org', + }, + ) const userBearerToken = encode({ id: 'u3' }) req = { headers: { authorization: `Bearer ${userBearerToken}` } } }) @@ -172,10 +176,13 @@ describe('login', () => { beforeEach(async () => { variables = { email: 'test@example.org', password: '1234' } - user = await factory.create('User', { - ...variables, - id: 'acb2d923-f3af-479e-9f00-61b12e864666', - }) + user = await Factory.build( + 'user', + { + id: 'acb2d923-f3af-479e-9f00-61b12e864666', + }, + variables, + ) }) describe('ask for a `token`', () => { @@ -295,7 +302,7 @@ describe('change password', () => { describe('authenticated', () => { beforeEach(async () => { - await factory.create('User', { id: 'u3' }) + await Factory.build('user', { id: 'u3' }) const userBearerToken = encode({ id: 'u3' }) req = { headers: { authorization: `Bearer ${userBearerToken}` } } }) diff --git a/backend/src/schema/resolvers/users.js b/backend/src/schema/resolvers/users.js index d1d9111b6..cbdc683e8 100644 --- a/backend/src/schema/resolvers/users.js +++ b/backend/src/schema/resolvers/users.js @@ -252,9 +252,11 @@ export default { followedByCurrentUser: 'MATCH (this)<-[:FOLLOWS]-(u:User {id: $cypherParams.currentUserId}) RETURN COUNT(u) >= 1', blocked: - 'MATCH (this)<-[:BLOCKED]-(u:User {id: $cypherParams.currentUserId}) RETURN COUNT(u) >= 1', + 'MATCH (this)-[:BLOCKED]-(u:User {id: $cypherParams.currentUserId}) RETURN COUNT(u) >= 1', isMuted: 'MATCH (this)<-[:MUTED]-(u:User {id: $cypherParams.currentUserId}) RETURN COUNT(u) >= 1', + isBlocked: + 'MATCH (this)<-[:BLOCKED]-(u:User {id: $cypherParams.currentUserId}) RETURN COUNT(u) >= 1', }, count: { contributionsCount: diff --git a/backend/src/schema/resolvers/users.spec.js b/backend/src/schema/resolvers/users.spec.js index cfd84fcf7..9e24b8082 100644 --- a/backend/src/schema/resolvers/users.spec.js +++ b/backend/src/schema/resolvers/users.spec.js @@ -1,10 +1,9 @@ -import Factory from '../../factories' +import Factory, { cleanDatabase } from '../../db/factories' import { gql } from '../../helpers/jest' import { getNeode, getDriver } from '../../db/neo4j' import createServer from '../../server' import { createTestClient } from 'apollo-server-testing' -const factory = Factory() const categoryIds = ['cat9'] let user @@ -31,13 +30,13 @@ beforeAll(() => { }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('User', () => { describe('query by email address', () => { beforeEach(async () => { - await factory.create('User', { name: 'Johnny', email: 'any-email-address@example.org' }) + await Factory.build('user', { name: 'Johnny' }, { email: 'any-email-address@example.org' }) }) const userQuery = gql` @@ -57,11 +56,16 @@ describe('User', () => { describe('as admin', () => { beforeEach(async () => { - const admin = await factory.create('User', { - role: 'admin', - email: 'admin@example.org', - password: '1234', - }) + const admin = await Factory.build( + 'user', + { + role: 'admin', + }, + { + email: 'admin@example.org', + password: '1234', + }, + ) authenticatedUser = await admin.toJson() }) @@ -91,19 +95,9 @@ describe('User', () => { }) describe('UpdateUser', () => { - let userParams, variables + let variables beforeEach(async () => { - userParams = { - email: 'user@example.org', - password: '1234', - id: 'u47', - name: 'John Doe', - termsAndConditionsAgreedVersion: null, - termsAndConditionsAgreedAt: null, - allowEmbedIframes: false, - } - variables = { id: 'u47', name: 'John Doughnut', @@ -133,18 +127,33 @@ describe('UpdateUser', () => { ` beforeEach(async () => { - user = await factory.create('User', userParams) + user = await Factory.build( + 'user', + { + id: 'u47', + name: 'John Doe', + termsAndConditionsAgreedVersion: null, + termsAndConditionsAgreedAt: null, + allowEmbedIframes: false, + }, + { + email: 'user@example.org', + }, + ) }) describe('as another user', () => { beforeEach(async () => { - const someoneElseParams = { - email: 'someone-else@example.org', - password: '1234', - name: 'James Doe', - } + const someoneElse = await Factory.build( + 'user', + { + name: 'James Doe', + }, + { + email: 'someone-else@example.org', + }, + ) - const someoneElse = await factory.create('User', someoneElseParams) authenticatedUser = await someoneElse.toJson() }) @@ -267,16 +276,20 @@ describe('DeleteUser', () => { beforeEach(async () => { variables = { id: ' u343', resource: [] } - user = await factory.create('User', { + user = await Factory.build('user', { name: 'My name should be deleted', about: 'along with my about', id: 'u343', }) - await factory.create('User', { - email: 'friends-account@example.org', - password: '1234', - id: 'not-my-account', - }) + await Factory.build( + 'user', + { + id: 'not-my-account', + }, + { + email: 'friends-account@example.org', + }, + ) }) describe('unauthenticated', () => { @@ -309,27 +322,42 @@ describe('DeleteUser', () => { describe('given posts and comments', () => { beforeEach(async () => { - await factory.create('Category', { + await Factory.build('category', { id: 'cat9', name: 'Democracy & Politics', icon: 'university', }) - await factory.create('Post', { - author: user, - id: 'p139', - content: 'Post by user u343', - categoryIds, - }) - await factory.create('Comment', { - author: user, - id: 'c155', - content: 'Comment by user u343', - }) - await factory.create('Comment', { - postId: 'p139', - id: 'c156', - content: "A comment by someone else on user u343's post", - }) + await Factory.build( + 'post', + { + id: 'p139', + content: 'Post by user u343', + }, + { + author: user, + categoryIds, + }, + ) + await Factory.build( + 'comment', + { + id: 'c155', + content: 'Comment by user u343', + }, + { + author: user, + }, + ) + await Factory.build( + 'comment', + { + id: 'c156', + content: "A comment by someone else on user u343's post", + }, + { + postId: 'p139', + }, + ) }) it("deletes my account, but doesn't delete posts or comments by default", async () => { @@ -527,7 +555,7 @@ describe('DeleteUser', () => { describe('connected `SocialMedia` nodes', () => { beforeEach(async () => { - const socialMedia = await factory.create('SocialMedia') + const socialMedia = await Factory.build('socialMedia') await socialMedia.relateTo(user, 'ownedBy') }) diff --git a/backend/src/schema/resolvers/users/location.spec.js b/backend/src/schema/resolvers/users/location.spec.js index f7315174c..5b9a49a6a 100644 --- a/backend/src/schema/resolvers/users/location.spec.js +++ b/backend/src/schema/resolvers/users/location.spec.js @@ -1,10 +1,9 @@ import { gql } from '../../../helpers/jest' -import Factory from '../../../factories' +import Factory, { cleanDatabase } from '../../../db/factories' import { getNeode, getDriver } from '../../../db/neo4j' import { createTestClient } from 'apollo-server-testing' import createServer from '../../../server' -const factory = Factory() const neode = getNeode() const driver = getDriver() let authenticatedUser, mutate, variables @@ -107,7 +106,7 @@ beforeEach(() => { }) afterEach(() => { - factory.cleanDatabase() + cleanDatabase() }) describe('userMiddleware', () => { @@ -146,7 +145,7 @@ describe('userMiddleware', () => { }) describe('UpdateUser', () => { - let user, userParams + let user beforeEach(async () => { newlyCreatedNodesWithLocales = [ { @@ -182,10 +181,9 @@ describe('userMiddleware', () => { }, }, ] - userParams = { + user = await Factory.build('user', { id: 'updating-user', - } - user = await factory.create('User', userParams) + }) authenticatedUser = await user.toJson() }) diff --git a/backend/src/schema/resolvers/users/mutedUsers.spec.js b/backend/src/schema/resolvers/users/mutedUsers.spec.js index 130df08ce..cdc7c81b3 100644 --- a/backend/src/schema/resolvers/users/mutedUsers.spec.js +++ b/backend/src/schema/resolvers/users/mutedUsers.spec.js @@ -1,11 +1,10 @@ import { createTestClient } from 'apollo-server-testing' import createServer from '../../../server' -import Factory from '../../../factories' +import { cleanDatabase } from '../../../db/factories' import { gql } from '../../../helpers/jest' import { getNeode, getDriver } from '../../../db/neo4j' const driver = getDriver() -const factory = Factory() const neode = getNeode() let currentUser @@ -30,7 +29,7 @@ beforeEach(() => { }) afterEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) describe('mutedUsers', () => { diff --git a/backend/src/schema/types/type/User.gql b/backend/src/schema/types/type/User.gql index 71cc1edb0..baefc9d29 100644 --- a/backend/src/schema/types/type/User.gql +++ b/backend/src/schema/types/type/User.gql @@ -68,7 +68,12 @@ type User { RETURN COUNT(u) >= 1 """ ) - + isBlocked: Boolean! @cypher( + statement: """ + MATCH (this)<-[:BLOCKED]-(user:User {id: $cypherParams.currentUserId}) + RETURN COUNT(user) >= 1 + """ + ) blocked: Boolean! @cypher( statement: """ MATCH (this)-[:BLOCKED]-(user:User {id: $cypherParams.currentUserId}) diff --git a/backend/test/features/support/steps.js b/backend/test/features/support/steps.js index 70802f4e2..e11c69faa 100644 --- a/backend/test/features/support/steps.js +++ b/backend/test/features/support/steps.js @@ -3,18 +3,18 @@ import { Given, When, Then, AfterAll } from 'cucumber' import { expect } from 'chai' // import { client } from '../../../src/activitypub/apollo-client' import { GraphQLClient } from 'graphql-request' -import Factory from '../../../src/factories' +import Factory from '../../../src/db/factories' const debug = require('debug')('ea:test:steps') -const factory = Factory() const client = new GraphQLClient(host) function createUser (slug) { debug(`creating user ${slug}`) - return factory.create('User', { + return Factory.build('user', { name: slug, - email: 'example@test.org', + }, { password: '1234' + email: 'example@test.org', }) // await login({ email: 'example@test.org', password: '1234' }) } diff --git a/backend/yarn.lock b/backend/yarn.lock index a3011433e..466dc9bdc 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -4495,10 +4495,10 @@ graphql-redis-subscriptions@^2.1.2: optionalDependencies: ioredis "^4.6.3" -graphql-shield@~7.0.10: - version "7.0.10" - resolved "https://registry.yarnpkg.com/graphql-shield/-/graphql-shield-7.0.10.tgz#c25517a07e97bfd74089fde66ea2d2044addf743" - integrity sha512-m1HPQ3DpzuW8b7derWcsjjYtiBk+Hjgb1eL/0YK/Y2A0EV7vDQzJwRzlIwn9My7Xv+F4DJwm25yydnnUNpZt8g== +graphql-shield@~7.0.11: + version "7.0.11" + resolved "https://registry.yarnpkg.com/graphql-shield/-/graphql-shield-7.0.11.tgz#78d49f346326be71090d35d8f5843da9ee8136e2" + integrity sha512-iWn/aiom2c8NuOj60euWTmsKKUjX1DB4ynBcDitQOLXG3WrWgss2Iolzr553qooJvkR5czeAFgPlZgI+nUgwsQ== dependencies: "@types/yup" "0.26.30" object-hash "^2.0.0" @@ -7815,6 +7815,11 @@ rimraf@^3.0.0: dependencies: glob "^7.1.3" +rosie@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/rosie/-/rosie-2.0.1.tgz#c250c4787ce450b72aa9eff26509f68589814fa2" + integrity sha1-wlDEeHzkULcqqe/yZQn2hYmBT6I= + router-ips@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/router-ips/-/router-ips-1.0.0.tgz#44e00858ebebc0133d58e40b2cd8a1fbb04203f5" diff --git a/cypress/integration/common/report.js b/cypress/integration/common/report.js index 710928ff2..664d71d1b 100644 --- a/cypress/integration/common/report.js +++ b/cypress/integration/common/report.js @@ -30,11 +30,12 @@ Given("I see David Irving's post on the post page", page => { }) Given('I am logged in with a {string} role', role => { - cy.factory().create('User', { - email: `${role}@example.org`, - password: '1234', + cy.factory().build('user', { termsAndConditionsAgreedVersion: VERSION, role + }, { + email: `${role}@example.org`, + password: '1234', }) cy.login({ email: `${role}@example.org`, @@ -127,7 +128,7 @@ Given('somebody reported the following posts:', table => { password: '1234' } cy.factory() - .create('User', submitter) + .build('user', {}, submitter) .authenticateAs(submitter) .mutate(gql`mutation($resourceId: ID!, $reasonCategory: ReasonCategory!, $reasonDescription: String!) { fileReport(resourceId: $resourceId, reasonCategory: $reasonCategory, reasonDescription: $reasonDescription) { @@ -166,8 +167,9 @@ Then('I can visit the post page', () => { When("they have a post someone has reported", () => { cy.factory() - .create("Post", { - authorId: 'annnoying-user', + .build("post", { title, + }, { + authorId: 'annnoying-user', }); }) diff --git a/cypress/integration/common/steps.js b/cypress/integration/common/steps.js index 36dbb50d4..c51290537 100644 --- a/cypress/integration/common/steps.js +++ b/cypress/integration/common/steps.js @@ -25,7 +25,6 @@ const narratorParams = { name: "Peter Pan", slug: "peter-pan", avatar: "https://s3.amazonaws.com/uifaces/faces/twitter/nerrsoft/128.jpg", - ...loginCredentials, ...termsAndConditionsAgreedVersion, }; @@ -33,7 +32,6 @@ const annoyingParams = { email: "spammy-spammer@example.org", slug: 'spammy-spammer', password: "1234", - ...termsAndConditionsAgreedVersion }; Given("I am logged in", () => { @@ -49,49 +47,35 @@ Given("the {string} user searches for {string}", (_, postTitle) => { }); Given("we have a selection of categories", () => { - cy.createCategories("cat0", "just-for-fun"); + cy.factory().build('category', { id: "cat0", slug: "just-for-fun" }); }); Given("we have a selection of tags and categories as well as posts", () => { - cy.createCategories("cat12") - .factory() - .create("Tag", { - id: "Ecology" - }) - .create("Tag", { - id: "Nature" - }) - .create("Tag", { - id: "Democracy" - }); - cy.factory() - .create("User", { - id: 'a1' - }) - .create("Post", { + .build('category', { id: 'cat12', name: "Just For Fun", icon: "smile", }) + .build('category', { id: 'cat121', name: "Happiness & Values", icon: "heart-o"}) + .build('category', { id: 'cat122', name: "Health & Wellbeing", icon: "medkit"}) + .build("tag", { id: "Ecology" }) + .build("tag", { id: "Nature" }) + .build("tag", { id: "Democracy" }) + .build("user", { id: 'a1' }) + .build("post", {}, { authorId: 'a1', tagIds: ["Ecology", "Nature", "Democracy"], categoryIds: ["cat12"] }) - .create("Post", { + .build("post", {}, { authorId: 'a1', tagIds: ["Nature", "Democracy"], categoryIds: ["cat121"] - }); - - cy.factory() - .create("User", { - id: 'a2' }) - .create("Post", { + .build("user", { id: 'a2' }) + .build("post", {}, { authorId: 'a2', tagIds: ['Nature', 'Democracy'], categoryIds: ["cat12"] - }); - cy.factory() - .create("Post", { - authorId: narratorParams.id, + }) + .build("post", {}, { tagIds: ['Democracy'], categoryIds: ["cat122"] }) @@ -99,23 +83,22 @@ Given("we have a selection of tags and categories as well as posts", () => { Given("we have the following user accounts:", table => { table.hashes().forEach(params => { - cy.factory().create("User", { + cy.factory().build("user", { ...params, ...termsAndConditionsAgreedVersion - }); + }, params); }); }); Given("I have a user account", () => { - cy.factory().create("User", narratorParams); + cy.factory().build("user", narratorParams, loginCredentials); }); Given("my user account has the role {string}", role => { - cy.factory().create("User", { + cy.factory().build("user", { role, - ...loginCredentials, ...termsAndConditionsAgreedVersion, - }); + }, loginCredentials); }); When("I log out", cy.logout); @@ -203,30 +186,34 @@ When("I press {string}", label => { cy.contains(label).click(); }); -Given("we have this user in our database:", table => { - const [firstRow] = table.hashes() - cy.factory().create('User', firstRow) -}) +Given("we have the following comments in our database:", table => { + table.hashes().forEach((attributesOrOptions, i) => { + cy.factory().build("comment", { + ...attributesOrOptions, + }, { + ...attributesOrOptions, + }); + }) +}); Given("we have the following posts in our database:", table => { - cy.factory().create('Category', { + cy.factory().build('category', { id: `cat-456`, name: "Just For Fun", slug: `just-for-fun`, icon: "smile" }) - table.hashes().forEach(({ - ...postAttributes - }, i) => { - postAttributes = { - ...postAttributes, - deleted: Boolean(postAttributes.deleted), - disabled: Boolean(postAttributes.disabled), - pinned: Boolean(postAttributes.pinned), + table.hashes().forEach((attributesOrOptions, i) => { + cy.factory().build("post", { + ...attributesOrOptions, + deleted: Boolean(attributesOrOptions.deleted), + disabled: Boolean(attributesOrOptions.disabled), + pinned: Boolean(attributesOrOptions.pinned), + }, { + ...attributesOrOptions, categoryIds: ['cat-456'] - } - cy.factory().create("Post", postAttributes); + }); }) }); @@ -246,11 +233,15 @@ When( ); Given("I previously created a post", () => { - lastPost.authorId = narratorParams.id - lastPost.title = "previously created post"; - lastPost.content = "with some content"; + lastPost = { + lastPost, + title: "previously created post", + content: "with some content", + }; cy.factory() - .create("Post", lastPost); + .build("post", lastPost, { + authorId: narratorParams.id + }); }); When("I choose {string} as the title of the post", title => { @@ -318,10 +309,9 @@ Then( Given("my user account has the following login credentials:", table => { loginCredentials = table.hashes()[0]; cy.debug(); - cy.factory().create("User", { + cy.factory().build("user", { ...termsAndConditionsAgreedVersion, - ...loginCredentials - }); + }, loginCredentials); }); When("I fill the password form with:", table => { @@ -428,12 +418,11 @@ Then("there are no notifications in the top menu", () => { }); Given("there is an annoying user called {string}", name => { - cy.factory().create("User", { - ...annoyingParams, + cy.factory().build("user", { id: "annoying-user", name, ...termsAndConditionsAgreedVersion, - }); + }, annoyingParams); }); Given("there is an annoying user who has muted me", () => { @@ -498,12 +487,11 @@ Given("I follow the user {string}", name => { }); Given('{string} wrote a post {string}', (_, title) => { - cy.createCategories("cat21") - .factory() - .create("Post", { - authorId: 'annoying-user', + cy.factory() + .build("post", { title, - categoryIds: ["cat21"] + }, { + authorId: 'annoying-user', }); }); @@ -521,12 +509,11 @@ Then("I get removed from his follower collection", () => { }); Given("I wrote a post {string}", title => { - cy.createCategories(`cat213`, title) - .factory() - .create("Post", { - authorId: narratorParams.id, + cy.factory() + .build("post", { title, - categoryIds: ["cat213"] + }, { + authorId: narratorParams.id, }); }); @@ -552,7 +539,21 @@ When("I block the user {string}", name => { .then(blockedUser => { cy.neode() .first("User", { - name: narratorParams.name + id: narratorParams.id + }) + .relateTo(blockedUser, "blocked"); + }); +}); + +When("a user has blocked me", () => { + cy.neode() + .first("User", { + name: narratorParams.name + }) + .then(blockedUser => { + cy.neode() + .first("User", { + name: 'Harassing User' }) .relateTo(blockedUser, "blocked"); }); @@ -577,10 +578,31 @@ Then("I see only one post with the title {string}", title => { cy.get(".main-container").contains(".post-link", title); }); -Then("they should not see the comment from", () => { +Then("they should not see the comment form", () => { cy.get(".ds-card-footer").children().should('not.have.class', 'comment-form') }) -Then("they should see a text explaining commenting is not possible", () => { +Then("they should see a text explaining why commenting is not possible", () => { cy.get('.ds-placeholder').should('contain', "Commenting is not possible at this time on this post.") -}) \ No newline at end of file +}) + +Then("I should see no users in my blocked users list", () => { + cy.get('.ds-placeholder') + .should('contain', "So far, you have not blocked anybody.") +}) + +Then("I {string} see {string} from the content menu in the user info box", (condition, link) => { + cy.get(".user-content-menu .base-button").click() + cy.get(".popover .ds-menu-item-link") + .should(condition === 'should' ? 'contain' : 'not.contain', link) +}) + +Then('I should not see {string} button', button => { + cy.get('.ds-card-content .action-buttons') + .should('have.length', 1) +}) + +Then('I should see the {string} button', button => { + cy.get('.ds-card-content .action-buttons .base-button') + .should('contain', button) +}) diff --git a/cypress/integration/post/Comment.feature b/cypress/integration/post/Comment.feature index 66cf7a6d7..da261726b 100644 --- a/cypress/integration/post/Comment.feature +++ b/cypress/integration/post/Comment.feature @@ -6,8 +6,11 @@ Feature: Post Comment Background: Given I have a user account And we have the following posts in our database: - | id | title | slug | authorId | commentContent | - | bWBjpkTKZp | 101 Essays that will change the way you think | 101-essays | id-of-peter-pan | @peter-pan reply to me | + | id | title | slug | authorId | + | bWBjpkTKZp | 101 Essays that will change the way you think | 101-essays | id-of-peter-pan | + And we have the following comments in our database: + | postId | content | authorId | + | bWBjpkTKZp | @peter-pan reply to me | id-of-peter-pan | And I am logged in Scenario: Comment creation diff --git a/cypress/integration/user_profile/BlockUser.feature b/cypress/integration/user_profile/BlockUser.feature index 43efe7807..256d79dfb 100644 --- a/cypress/integration/user_profile/BlockUser.feature +++ b/cypress/integration/user_profile/BlockUser.feature @@ -11,6 +11,7 @@ Feature: Block a User Scenario: Block a user Given I am on the profile page of the annoying user When I click on "Block user" from the content menu in the user info box + And I "should" see "Unblock user" from the content menu in the user info box And I navigate to my "Blocked users" settings page Then I can see the following table: | Avatar | Name | @@ -20,14 +21,15 @@ Feature: Block a User Given I block the user "Harassing User" And I previously created a post And a blocked user visits the post page of one of my authored posts - Then they should not see the comment from - And they should see a text explaining commenting is not possible + Then they should see a text explaining why commenting is not possible + And they should not see the comment form Scenario: Block a previously followed user Given I follow the user "Harassing User" When I visit the profile page of the annoying user And I click on "Block user" from the content menu in the user info box And I get removed from his follower collection + And I "should" see "Unblock user" from the content menu in the user info box Scenario: Posts of blocked users are not filtered from search results Given "Harassing User" wrote a post "You can still see my posts" @@ -44,3 +46,15 @@ Feature: Block a User Then I should see the following posts in the select dropdown: | title | | previously created post | + + Scenario: Blocked users cannot see they are blocked in their list + Given a user has blocked me + And I navigate to my "Blocked users" settings page + Then I should see no users in my blocked users list + + Scenario: Blocked users should not see link or button to unblock, only blocking users + Given a user has blocked me + When I visit the profile page of the annoying user + And I "should not" see "Unblock user" from the content menu in the user info box + And I should see the "Follow" button + And I should not see "Unblock user" button \ No newline at end of file diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 16ac43a19..a8ef25e7d 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -74,27 +74,6 @@ Cypress.Commands.add("openPage", page => { cy.visit(`/${page}`); }); -Cypress.Commands.add("createCategories", (id, slug) => { - cy.neode() - .create("Category", { - id: `${id}`, - name: "Just For Fun", - slug: `${slug}`, - icon: "smile" - }) - .create("Category", { - id: `${id}1`, - name: "Happiness & Values", - icon: "heart-o" - }) - .create("Category", { - id: `${id}2`, - name: "Health & Wellbeing", - icon: "medkit" - }); -}); - - Cypress.Commands.add( 'authenticateAs', async ({email, password}) => { diff --git a/cypress/support/factories.js b/cypress/support/factories.js index 1b76a1a01..bee0d8542 100644 --- a/cypress/support/factories.js +++ b/cypress/support/factories.js @@ -1,4 +1,4 @@ -import Factory from '../../backend/src/factories' +import Factory, { cleanDatabase } from '../../backend/src/db/factories' import { getDriver, getNeode } from '../../backend/src/db/neo4j' const neo4jConfigs = { @@ -6,18 +6,16 @@ const neo4jConfigs = { username: Cypress.env('NEO4J_USERNAME'), password: Cypress.env('NEO4J_PASSWORD') } -const neo4jDriver = getDriver(neo4jConfigs) const neodeInstance = getNeode(neo4jConfigs) -const factoryOptions = { neo4jDriver, neodeInstance } -const factory = Factory(factoryOptions) beforeEach(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) Cypress.Commands.add('neode', () => { return neodeInstance }) + Cypress.Commands.add( 'first', { prevSubject: true }, @@ -33,24 +31,14 @@ Cypress.Commands.add( } ) -Cypress.Commands.add('factory', () => { - return Factory(factoryOptions) -}) +Cypress.Commands.add('factory', () => Factory) Cypress.Commands.add( - 'create', + 'build', { prevSubject: true }, - async (factory, node, properties) => { - await factory.create(node, properties) + async (factory, name, atrributes, options) => { + await factory.build(name, atrributes, options) return factory } ) -Cypress.Commands.add( - 'relate', - { prevSubject: true }, - async (factory, node, relationship, properties) => { - await factory.relate(node, relationship, properties) - return factory - } -) diff --git a/features/support/steps.js b/features/support/steps.js index 71f493834..67127fa1e 100644 --- a/features/support/steps.js +++ b/features/support/steps.js @@ -1,15 +1,13 @@ // features/support/steps.js import { Given, When, Then, After, AfterAll } from 'cucumber' -import Factory from '../../backend/src/factories' +import Factory, { cleanDatabase } from '../../backend/src/db/factories' import dotenv from 'dotenv' import expect from 'expect' const debug = require('debug')('ea:test:steps') -const factory = Factory() - After(async () => { - await factory.cleanDatabase() + await cleanDatabase() }) Given('our CLIENT_URI is {string}', function (string) { @@ -21,7 +19,7 @@ Given('our CLIENT_URI is {string}', function (string) { Given('we have the following users in our database:', function (dataTable) { return Promise.all(dataTable.hashes().map(({ slug, name }) => { - return factory.create('User', { + return Factory.build('user', { name, slug, }) diff --git a/package.json b/package.json index caed8a5b2..f50c1dadf 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "@babel/register": "^7.8.3", "auto-changelog": "^1.16.2", "bcryptjs": "^2.4.3", - "codecov": "^3.6.4", + "codecov": "^3.6.5", "cross-env": "^6.0.3", "cucumber": "^6.0.5", "cypress": "^3.8.3", @@ -46,6 +46,7 @@ "neo4j-driver": "^4.0.1", "neode": "^0.3.7", "npm-run-all": "^4.1.5", + "rosie": "^2.0.1", "slug": "^2.1.1", "standard-version": "^7.1.0" }, diff --git a/webapp/components/ContentMenu/ContentMenu.vue b/webapp/components/ContentMenu/ContentMenu.vue index ee2bd4a62..cee8a6f5c 100644 --- a/webapp/components/ContentMenu/ContentMenu.vue +++ b/webapp/components/ContentMenu/ContentMenu.vue @@ -172,7 +172,7 @@ export default { icon: 'microphone-slash', }) } - if (this.resource.blocked) { + if (this.resource.isBlocked) { routes.push({ label: this.$t(`settings.blocked-users.unblock`), callback: () => { diff --git a/webapp/graphql/User.js b/webapp/graphql/User.js index 65fdf6d10..fb0c4dddd 100644 --- a/webapp/graphql/User.js +++ b/webapp/graphql/User.js @@ -24,6 +24,7 @@ export default i18n => { createdAt followedByCurrentUser isMuted + isBlocked blocked following(first: 7) { ...user diff --git a/webapp/package.json b/webapp/package.json index 620a53165..0d36bef1d 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -103,7 +103,7 @@ "@storybook/addon-actions": "^5.3.12", "@storybook/addon-notes": "^5.3.12", "@storybook/vue": "~5.3.12", - "@vue/cli-shared-utils": "~4.1.2", + "@vue/cli-shared-utils": "~4.2.2", "@vue/eslint-config-prettier": "~6.0.0", "@vue/server-test-utils": "~1.0.0-beta.31", "@vue/test-utils": "~1.0.0-beta.31", diff --git a/webapp/pages/post/_id/_slug/index.vue b/webapp/pages/post/_id/_slug/index.vue index 1d107941a..8115294c5 100644 --- a/webapp/pages/post/_id/_slug/index.vue +++ b/webapp/pages/post/_id/_slug/index.vue @@ -97,7 +97,7 @@ :post="post" @createComment="createComment" /> - + {{ $t('settings.blocked-users.explanation.commenting-disabled') }}
{{ $t('settings.blocked-users.explanation.commenting-explanation') }} diff --git a/webapp/pages/profile/_id/_slug.vue b/webapp/pages/profile/_id/_slug.vue index 80471fff4..372b73b40 100644 --- a/webapp/pages/profile/_id/_slug.vue +++ b/webapp/pages/profile/_id/_slug.vue @@ -67,14 +67,14 @@
- + {{ $t('settings.blocked-users.unblock') }} {{ $t('settings.muted-users.unmute') }}