fix tests

This commit is contained in:
Hongbo Wu 2023-09-06 19:31:34 +08:00
parent bab957256d
commit 50bfc1fa74
25 changed files with 469 additions and 858 deletions

View file

@ -100,3 +100,19 @@ export const deleteHighlightById = async (highlightId: string) => {
return highlight
})
}
export const findHighlightById = async (
highlightId: string,
userId: string
) => {
return authTrx(
async (tx) => {
const highlightRepo = tx.withRepository(highlightRepository)
return highlightRepo.findOneByOrFail({
id: highlightId,
})
},
undefined,
userId
)
}

View file

@ -489,3 +489,31 @@ export const updateLibraryItems = async (
return queryBuilder.update(LibraryItem).set(values).execute()
})
}
export const deleteLibraryItemById = async (id: string, userId?: string) => {
return authTrx(
async (tx) => tx.withRepository(libraryItemRepository).delete(id),
undefined,
userId
)
}
export const deleteLibraryItemByUrl = async (url: string, userId?: string) => {
return authTrx(
async (tx) =>
tx.withRepository(libraryItemRepository).delete({ originalUrl: url }),
undefined,
userId
)
}
export const deleteLibraryItemByUserId = async (userId: string) => {
return authTrx(
async (tx) =>
tx.withRepository(libraryItemRepository).delete({
user: { id: userId },
}),
undefined,
userId
)
}

View file

@ -4,16 +4,15 @@ import { SnakeNamingStrategy } from 'typeorm-naming-strategies'
import { appDataSource } from '../src/data_source'
import { Integration } from '../src/entity/integration'
import { Label } from '../src/entity/label'
import { Link } from '../src/entity/link'
import { NewsletterEmail } from '../src/entity/newsletter_email'
import { Page } from '../src/entity/page'
import { Profile } from '../src/entity/profile'
import { Reminder } from '../src/entity/reminder'
import { Subscription } from '../src/entity/subscription'
import { User } from '../src/entity/user'
import { UserDeviceToken } from '../src/entity/user_device_tokens'
import { SubscriptionStatus, SubscriptionType } from '../src/generated/graphql'
import { getRepository, setClaims, userRepository } from '../src/repository'
import { getRepository, setClaims } from '../src/repository'
import { userRepository } from '../src/repository/user'
import { createUser } from '../src/services/create_user'
import { Filter } from "../src/entity/filter"
@ -118,28 +117,6 @@ export const getProfile = async (user: User): Promise<Profile | null> => {
return getRepository(Profile).findOneBy({ user: { id: user.id } })
}
export const createTestPage = async (): Promise<Page> => {
return getRepository(Page).save({
originalHtml: 'html',
content: 'Test content',
description: 'Test description',
title: 'Test title',
author: 'Test author',
url: 'Test url',
hash: 'Test hash',
})
}
export const createTestLink = async (user: User, page: Page): Promise<Link> => {
return getRepository(Link).save({
user: user,
page: page,
slug: 'Test slug',
articleUrl: 'Test url',
articleHash: 'Test hash',
})
}
export const createTestReminder = async (
user: User,
pageId?: string
@ -192,10 +169,6 @@ export const getUser = async (id: string): Promise<User | null> => {
return userRepository.findOneBy({ id })
}
export const getLink = async (id: string): Promise<Link | null> => {
return getRepository(Link).findOneBy({ id })
}
export const createTestLabel = async (
user: User,
name: string,

View file

@ -3,42 +3,37 @@ import { expect } from 'chai'
import chaiString from 'chai-string'
import 'mocha'
import sinon from 'sinon'
import { refreshIndex } from '../../src/elastic'
import { addHighlightToPage } from '../../src/elastic/highlights'
import {
createPage,
deletePage,
deletePagesByParam,
getPageById,
getPageByParam,
updatePage,
} from '../../src/elastic/pages'
import {
ArticleSavingRequestStatus,
Highlight,
HighlightType,
Page,
PageContext,
PageType,
} from '../../src/elastic/types'
import { DeepPartial } from 'typeorm'
import { Highlight } from '../../src/entity/highlight'
import { LibraryItem, LibraryItemState, LibraryItemType } from '../../src/entity/library_item'
import { UploadFile } from '../../src/entity/upload_file'
import { User } from '../../src/entity/user'
import {
ArticleSavingRequestStatus,
BulkActionType,
SyncUpdatedItemEdge,
UpdateReason,
UploadFileStatus,
UploadFileStatus
} from '../../src/generated/graphql'
import { createPubSubClient } from '../../src/pubsub'
import { getRepository } from '../../src/repository'
import { createHighlight } from '../../src/services/highlights'
import {
createLibraryItem,
deleteLibraryItemById,
deleteLibraryItemByUrl,
deleteLibraryItemByUserId,
findLibraryItemById,
findLibraryItemByUrl,
updateLibraryItem
} from '../../src/services/library_item'
import * as createTask from '../../src/utils/createTask'
import * as uploads from '../../src/utils/uploads'
import { createTestUser, deleteTestUser } from '../db'
import {
createTestElasticPage,
createTestLibraryItem,
generateFakeUuid,
graphqlRequest,
request,
request
} from '../util'
chai.use(chaiString)
@ -376,7 +371,6 @@ const typeaheadSearchQuery = (keyword: string) => {
describe('Article API', () => {
let authToken: string
let user: User
let ctx: PageContext
before(async () => {
// create test user and login
@ -386,12 +380,6 @@ describe('Article API', () => {
.send({ fakeEmail: user.email })
authToken = res.body.authToken
ctx = {
pubsub: createPubSubClient(),
refresh: true,
uid: user.id,
}
})
after(async () => {
@ -405,7 +393,7 @@ describe('Article API', () => {
let source = ''
let document = ''
let title = ''
let pageId = ''
let itemId = ''
beforeEach(async () => {
query = createArticleQuery(url, source, document, title)
@ -420,14 +408,14 @@ describe('Article API', () => {
})
after(async () => {
await deletePage(pageId, ctx)
await deleteLibraryItemById(itemId, user.id)
})
it('should create an article', async () => {
const res = await graphqlRequest(query, authToken).expect(200)
expect(res.body.data.createArticle.createdArticle.title).to.eql(title)
pageId = res.body.data.createArticle.createdArticle.id
itemId = res.body.data.createArticle.createdArticle.id
})
})
@ -438,29 +426,23 @@ describe('Article API', () => {
document = '<p>test</p>'
title = 'new title'
pageId = (await createPage(
const item = await createLibraryItem(
{
content: document,
createdAt: new Date(),
hash: 'test hash',
id: '',
pageType: PageType.Article,
readingProgressAnchorIndex: 0,
readingProgressPercent: 0,
savedAt: new Date(),
readableContent: document,
slug: 'test saving an archived article slug',
state: ArticleSavingRequestStatus.Succeeded,
title,
userId: user.id,
url,
user: { id: user.id },
originalUrl: url,
archivedAt: new Date(),
state: LibraryItemState.Archived,
},
ctx
))!
user.id
)
itemId = item.id
})
after(async () => {
await deletePage(pageId, ctx)
await deleteLibraryItemById(itemId, user.id)
})
it('unarchives the article', async () => {
@ -476,42 +458,32 @@ describe('Article API', () => {
let query = ''
let slug = ''
let pageId: string
let itemId: string
before(async () => {
const page: Page = {
state: ArticleSavingRequestStatus.Succeeded,
id: '',
hash: 'test hash',
userId: user.id,
pageType: PageType.Article,
const itemToCreate: DeepPartial<LibraryItem> = {
title: 'test title',
content: '<p>test</p>',
originalContent: '<p>test</p>',
slug: realSlug,
createdAt: new Date(),
updatedAt: new Date(),
readingProgressPercent: 100,
readingProgressAnchorIndex: 0,
url: 'https://blog.omnivore.app/test-with-omnivore',
savedAt: new Date(),
readingProgressTopPercent: 100,
user,
originalUrl: 'https://blog.omnivore.app/test-with-omnivore',
highlights: [
{
id: 'test id',
id: generateFakeUuid(),
shortId: 'test short id',
createdAt: new Date(),
patch: 'test patch',
quote: 'test quote',
updatedAt: new Date(),
userId: user.id,
type: HighlightType.Highlight,
user,
},
],
}
pageId = (await createPage(page, ctx))!
const item = await createLibraryItem(itemToCreate, user.id)
itemId = item.id
})
after(async () => {
await deletePage(pageId, ctx)
await deleteLibraryItemById(itemId, user.id)
})
beforeEach(async () => {
@ -537,13 +509,13 @@ describe('Article API', () => {
context('when page is failed to process', () => {
before(async () => {
await updatePage(
pageId,
await updateLibraryItem(
itemId,
{
state: ArticleSavingRequestStatus.Processing,
state: LibraryItemState.Processing,
savedAt: new Date(Date.now() - 1000 * 60),
},
ctx
user.id
)
})
@ -582,7 +554,7 @@ describe('Article API', () => {
context('when we save a new page', () => {
after(async () => {
await deletePagesByParam({ url }, ctx)
await deleteLibraryItemById(url, user.id)
})
it('should return a slugged url', async () => {
@ -599,7 +571,7 @@ describe('Article API', () => {
})
after(async () => {
await deletePagesByParam({ url }, ctx)
await deleteLibraryItemById(url, user.id)
})
it('it should return that page in the GetArticles Query', async () => {
@ -607,17 +579,14 @@ describe('Article API', () => {
savePageQuery(url, title, originalContent),
authToken
).expect(200)
await refreshIndex()
// Save a link, then archive it
// refresh the index to make sure the page is updated
let allLinks = await graphqlRequest(
articlesQuery(''),
authToken
).expect(200)
const justSavedId = allLinks.body.data.articles.edges[0].node.id
await archiveLink(authToken, justSavedId)
await refreshIndex()
// test the negative case, ensuring the archive link wasn't returned
allLinks = await graphqlRequest(articlesQuery(''), authToken).expect(
@ -630,7 +599,6 @@ describe('Article API', () => {
savePageQuery(url, title, originalContent),
authToken
).expect(200)
await refreshIndex()
allLinks = await graphqlRequest(articlesQuery(''), authToken).expect(
200
@ -641,7 +609,7 @@ describe('Article API', () => {
context('when we also want to save labels and archives the page', () => {
after(async () => {
await deletePagesByParam({ url }, ctx)
await deleteLibraryItemById(url, user.id)
})
it('saves the labels and archives the page', async () => {
@ -652,11 +620,10 @@ describe('Article API', () => {
savePageQuery(url, title, originalContent, state, labels),
authToken
).expect(200)
await refreshIndex()
const savedPage = await getPageByParam({ url })
expect(savedPage?.archivedAt).to.not.be.null
expect(savedPage?.labels?.map((l) => l.name)).to.eql(labels)
const savedItem = await findLibraryItemByUrl(url, user.id)
expect(savedItem?.archivedAt).to.not.be.null
expect(savedItem?.labels?.map((l) => l.name)).to.eql(labels)
})
})
})
@ -678,7 +645,7 @@ describe('Article API', () => {
})
afterEach(async () => {
await deletePagesByParam({ url }, ctx)
await deleteLibraryItemByUrl(url, user.id)
})
context('when we save a new url', () => {
@ -699,11 +666,10 @@ describe('Article API', () => {
saveUrlQuery(url, state, labels),
authToken
).expect(200)
await refreshIndex()
const savedPage = await getPageByParam({ url })
expect(savedPage?.archivedAt).to.not.be.null
expect(savedPage?.labels?.map((l) => l.name)).to.eql(labels)
const savedItem = await findLibraryItemByUrl(url, user.id)
expect(savedItem?.archivedAt).to.not.be.null
expect(savedItem?.labels?.map((l) => l.name)).to.eql(labels)
})
})
})
@ -712,29 +678,22 @@ describe('Article API', () => {
let query = ''
let articleId = ''
let bookmark = true
let pageId: string
let itemId: string
before(async () => {
const page: Page = {
id: '',
hash: 'test hash',
userId: user.id,
pageType: PageType.Article,
const itemToSave: DeepPartial<LibraryItem> = {
user,
title: 'test title',
content: '<p>test</p>',
createdAt: new Date(),
savedAt: new Date(),
url: 'https://blog.omnivore.app/setBookmarkArticle',
readableContent: '<p>test</p>',
originalUrl: 'https://blog.omnivore.app/setBookmarkArticle',
slug: 'test-with-omnivore',
readingProgressPercent: 0,
readingProgressAnchorIndex: 0,
state: ArticleSavingRequestStatus.Succeeded,
}
pageId = (await createPage(page, ctx))!
const item = await createLibraryItem(itemToSave, user.id)
itemId = item.id
})
after(async () => {
await deletePage(pageId, ctx)
await deleteLibraryItemById(itemId, user.id)
})
beforeEach(() => {
@ -743,7 +702,7 @@ describe('Article API', () => {
context('when we set a bookmark on an article', () => {
before(() => {
articleId = pageId
articleId = itemId
bookmark = true
})
@ -757,34 +716,34 @@ describe('Article API', () => {
context('when we unset a bookmark on an article', () => {
before(() => {
articleId = pageId
articleId = itemId
bookmark = false
})
it('should delete an article', async () => {
await graphqlRequest(query, authToken).expect(200)
const page = await getPageById(articleId)
expect(page?.state).to.eql(ArticleSavingRequestStatus.Deleted)
const item = await findLibraryItemById(articleId, user.id)
expect(item?.state).to.eql(ArticleSavingRequestStatus.Deleted)
})
})
})
describe('saveArticleReadingProgressResolver', () => {
let query = ''
let pageId = ''
let itemId = ''
let progress = 0.5
let topPercent: number | null = null
before(async () => {
pageId = (await createTestElasticPage(user.id)).id!
itemId = (await createTestLibraryItem(user.id)).id
})
after(async () => {
await deletePage(pageId, ctx)
await deleteLibraryItemById(itemId, user.id)
})
it('saves a reading progress on an article', async () => {
query = saveArticleReadingProgressQuery(pageId, progress, topPercent)
query = saveArticleReadingProgressQuery(itemId, progress, topPercent)
const res = await graphqlRequest(query, authToken).expect(200)
expect(
res.body.data.saveArticleReadingProgress.updatedArticle
@ -795,17 +754,16 @@ describe('Article API', () => {
})
it('should not allow setting the reading progress lower than current progress', async () => {
const firstQuery = saveArticleReadingProgressQuery(pageId, 75)
const firstQuery = saveArticleReadingProgressQuery(itemId, 75)
const firstRes = await graphqlRequest(firstQuery, authToken).expect(200)
expect(
firstRes.body.data.saveArticleReadingProgress.updatedArticle
.readingProgressPercent
).to.eq(75)
await refreshIndex()
// Now try to set to a lower value (50), value should not be updated
// refresh index to ensure the reading progress is updated
const secondQuery = saveArticleReadingProgressQuery(pageId, 50)
const secondQuery = saveArticleReadingProgressQuery(itemId, 50)
const secondRes = await graphqlRequest(secondQuery, authToken).expect(200)
expect(
secondRes.body.data.saveArticleReadingProgress.updatedArticle
@ -814,7 +772,7 @@ describe('Article API', () => {
})
it('does not save topPercent if not undefined', async () => {
query = saveArticleReadingProgressQuery(pageId, progress, null)
query = saveArticleReadingProgressQuery(itemId, progress, null)
const res = await graphqlRequest(query, authToken).expect(200)
expect(
res.body.data.saveArticleReadingProgress.updatedArticle
@ -824,7 +782,7 @@ describe('Article API', () => {
it('saves topPercent if defined', async () => {
const topPercent = 0.2
query = saveArticleReadingProgressQuery(pageId, progress, topPercent)
query = saveArticleReadingProgressQuery(itemId, progress, topPercent)
const res = await graphqlRequest(query, authToken).expect(200)
expect(
res.body.data.saveArticleReadingProgress.updatedArticle
@ -834,7 +792,7 @@ describe('Article API', () => {
it('saves topPercent as 0 if defined as 0', async () => {
const topPercent = 0
query = saveArticleReadingProgressQuery(pageId, progress, topPercent)
query = saveArticleReadingProgressQuery(itemId, progress, topPercent)
const res = await graphqlRequest(query, authToken).expect(200)
expect(
res.body.data.saveArticleReadingProgress.updatedArticle
@ -843,7 +801,7 @@ describe('Article API', () => {
})
it('returns BAD_DATA error if top position is greater than bottom position', async () => {
query = saveArticleReadingProgressQuery(pageId, 0.5, 0.8)
query = saveArticleReadingProgressQuery(itemId, 0.5, 0.8)
const res = await graphqlRequest(query, authToken).expect(200)
expect(res.body.data.saveArticleReadingProgress.errorCodes).to.eql([
'BAD_DATA',
@ -908,7 +866,7 @@ describe('Article API', () => {
describe('Search API', () => {
const url = 'https://blog.omnivore.app/p/getting-started-with-omnivore'
const pages: Page[] = []
const items: LibraryItem[] = []
const highlights: Highlight[] = []
const searchedKeyword = 'aaabbbccc'
@ -918,38 +876,27 @@ describe('Article API', () => {
before(async () => {
// Create some test pages
for (let i = 0; i < 5; i++) {
const page: Page = {
id: '',
hash: 'test hash',
userId: user.id,
pageType: PageType.Article,
const itemToSave: DeepPartial<LibraryItem> = {
user,
title: 'test title',
content: `<p>test ${searchedKeyword}</p>`,
readableContent: `<p>test ${searchedKeyword}</p>`,
slug: 'test slug',
createdAt: new Date(),
updatedAt: new Date(),
readingProgressPercent: 0,
readingProgressAnchorIndex: 0,
url: `${url}/${i}`,
savedAt: new Date(),
state: ArticleSavingRequestStatus.Succeeded,
originalUrl: `${url}/${i}`,
siteName: 'Example',
}
page.id = (await createPage(page, ctx))!
pages.push(page)
const item = await createLibraryItem(itemToSave, user.id)
items.push(item)
// Create some test highlights
const highlight: Highlight = {
id: `highlight-${i}`,
const highlightToSave: DeepPartial<Highlight> = {
patch: 'test patch',
shortId: 'test shortId',
userId: user.id,
user,
quote: '<p>search highlight</p>',
createdAt: new Date(),
updatedAt: new Date(),
type: HighlightType.Highlight,
}
await addHighlightToPage(page.id, highlight, ctx)
const highlight = await createHighlight(highlightToSave, item.id, user.id)
highlights.push(highlight)
}
})
@ -959,7 +906,7 @@ describe('Article API', () => {
})
after(async () => {
await deletePagesByParam({ userId: user.id }, ctx)
await deleteLibraryItemByUserId(user.id)
})
context('when type:highlights is not in the query', () => {
@ -971,11 +918,11 @@ describe('Article API', () => {
const res = await graphqlRequest(query, authToken).expect(200)
expect(res.body.data.search.edges.length).to.eql(5)
expect(res.body.data.search.edges[0].node.id).to.eq(pages[4].id)
expect(res.body.data.search.edges[1].node.id).to.eq(pages[3].id)
expect(res.body.data.search.edges[2].node.id).to.eq(pages[2].id)
expect(res.body.data.search.edges[3].node.id).to.eq(pages[1].id)
expect(res.body.data.search.edges[4].node.id).to.eq(pages[0].id)
expect(res.body.data.search.edges[0].node.id).to.eq(items[4].id)
expect(res.body.data.search.edges[1].node.id).to.eq(items[3].id)
expect(res.body.data.search.edges[2].node.id).to.eq(items[2].id)
expect(res.body.data.search.edges[3].node.id).to.eq(items[1].id)
expect(res.body.data.search.edges[4].node.id).to.eq(items[0].id)
})
it('should return highlights in pages', async () => {
@ -1014,11 +961,11 @@ describe('Article API', () => {
const res = await graphqlRequest(query, authToken).expect(200)
expect(res.body.data.search.edges.length).to.eq(5)
expect(res.body.data.search.edges[0].node.id).to.eq(pages[4].id)
expect(res.body.data.search.edges[1].node.id).to.eq(pages[3].id)
expect(res.body.data.search.edges[2].node.id).to.eq(pages[2].id)
expect(res.body.data.search.edges[3].node.id).to.eq(pages[1].id)
expect(res.body.data.search.edges[4].node.id).to.eq(pages[0].id)
expect(res.body.data.search.edges[0].node.id).to.eq(items[4].id)
expect(res.body.data.search.edges[1].node.id).to.eq(items[3].id)
expect(res.body.data.search.edges[2].node.id).to.eq(items[2].id)
expect(res.body.data.search.edges[3].node.id).to.eq(items[1].id)
expect(res.body.data.search.edges[4].node.id).to.eq(items[0].id)
})
})
@ -1060,7 +1007,7 @@ describe('Article API', () => {
})
describe('TypeaheadSearch API', () => {
const pages: Page[] = []
const items: LibraryItem[] = []
let query = ''
let keyword = 'typeahead'
@ -1068,24 +1015,15 @@ describe('Article API', () => {
before(async () => {
// Create some test pages
for (let i = 0; i < 5; i++) {
const page: Page = {
id: '',
hash: '',
userId: user.id,
pageType: PageType.Article,
const itemToSave: DeepPartial<LibraryItem> = {
user,
title: 'typeahead search page',
content: '',
readableContent: '<p>test</p>',
slug: '',
createdAt: new Date(),
updatedAt: new Date(),
readingProgressPercent: 0,
readingProgressAnchorIndex: 0,
url: '',
savedAt: new Date(),
state: ArticleSavingRequestStatus.Succeeded,
originalUrl: `https://blog.omnivore.app/p/typeahead-search-${i}`,
}
page.id = (await createPage(page, ctx))!
pages.push(page)
const item = await createLibraryItem(itemToSave, user.id)
items.push(item)
}
})
@ -1094,18 +1032,18 @@ describe('Article API', () => {
})
after(async () => {
await deletePagesByParam({ userId: user.id }, ctx)
await deleteLibraryItemByUserId(user.id)
})
it('should return pages with typeahead prefix', async () => {
const res = await graphqlRequest(query, authToken).expect(200)
expect(res.body.data.typeaheadSearch.items.length).to.eql(5)
expect(res.body.data.typeaheadSearch.items[0].id).to.eq(pages[0].id)
expect(res.body.data.typeaheadSearch.items[1].id).to.eq(pages[1].id)
expect(res.body.data.typeaheadSearch.items[2].id).to.eq(pages[2].id)
expect(res.body.data.typeaheadSearch.items[3].id).to.eq(pages[3].id)
expect(res.body.data.typeaheadSearch.items[4].id).to.eq(pages[4].id)
expect(res.body.data.typeaheadSearch.items[0].id).to.eq(items[0].id)
expect(res.body.data.typeaheadSearch.items[1].id).to.eq(items[1].id)
expect(res.body.data.typeaheadSearch.items[2].id).to.eq(items[2].id)
expect(res.body.data.typeaheadSearch.items[3].id).to.eq(items[3].id)
expect(res.body.data.typeaheadSearch.items[4].id).to.eq(items[4].id)
expect(res.body.data.typeaheadSearch.items[0].contentReader).to.eq('WEB')
})
})
@ -1142,49 +1080,39 @@ describe('Article API', () => {
}
`
let since: string
let pages: Page[] = []
let deletedPages: Page[] = []
let items: LibraryItem[] = []
let deletedItems: LibraryItem[] = []
before(async () => {
// Create some test pages
for (let i = 0; i < 5; i++) {
const page: Page = {
id: '',
hash: '',
userId: user.id,
pageType: PageType.Article,
const itemToSave: DeepPartial<LibraryItem> = {
title: 'test page',
content: '',
slug: '',
createdAt: new Date(),
updatedAt: new Date(),
readingProgressPercent: 0,
readingProgressAnchorIndex: 0,
url: '',
savedAt: new Date(),
state: ArticleSavingRequestStatus.Succeeded,
readableContent: '<p>test</p>',
originalUrl: `https://blog.omnivore.app/p/updates-since-${i}`,
}
page.id = (await createPage(page, ctx))!
pages.push(page)
const item = await createLibraryItem(itemToSave, user.id)
items.push(item)
}
// set the since to be the timestamp before deletion
since = pages[4].updatedAt!.toISOString()
since = items[4].updatedAt!.toISOString()
// Delete some pages
for (let i = 0; i < 3; i++) {
await updatePage(
pages[i].id,
{ state: ArticleSavingRequestStatus.Deleted },
ctx
await updateLibraryItem(
items[i].id,
{ state: LibraryItemState.Deleted },
user.id
)
deletedPages.push(pages[i])
deletedItems.push(items[i])
}
})
after(async () => {
// Delete all pages
await deletePagesByParam({ userId: user.id }, ctx)
await deleteLibraryItemByUserId(user.id)
})
it('returns pages deleted after since', async () => {
@ -1199,13 +1127,13 @@ describe('Article API', () => {
).length
).to.eql(3)
expect(res.body.data.updatesSince.edges[0].itemID).to.eq(
deletedPages[2].id
deletedItems[2].id
)
expect(res.body.data.updatesSince.edges[1].itemID).to.eq(
deletedPages[1].id
deletedItems[1].id
)
expect(res.body.data.updatesSince.edges[2].itemID).to.eq(
deletedPages[0].id
deletedItems[0].id
)
expect(res.body.data.updatesSince.edges[0].updateReason).to.eq(
UpdateReason.Deleted
@ -1230,34 +1158,27 @@ describe('Article API', () => {
before(async () => {
// Create some test pages
for (let i = 0; i < 5; i++) {
await createPage(
await createLibraryItem(
{
id: '',
hash: '',
userId: user.id,
pageType: i == 0 ? PageType.Article : PageType.File,
user,
itemType: i == 0 ? LibraryItemType.Article : LibraryItemType.File,
title: 'test page',
content: '',
readableContent: '<p>test</p>',
slug: '',
createdAt: new Date(),
updatedAt: new Date(),
readingProgressPercent: 0,
readingProgressAnchorIndex: 0,
url: '',
savedAt: new Date(),
state:
i == 0
? ArticleSavingRequestStatus.Failed
: ArticleSavingRequestStatus.Succeeded,
? LibraryItemState.Failed
: LibraryItemState.Succeeded,
originalUrl: `https://blog.omnivore.app/p/bulk-action-${i}`,
},
ctx
user.id
)
}
})
after(async () => {
// Delete all pages
await deletePagesByParam({ userId: user.id }, ctx)
await deleteLibraryItemByUserId(user.id)
})
context('when action is Archive', () => {
@ -1268,8 +1189,6 @@ describe('Article API', () => {
).expect(200)
expect(res.body.data.bulkAction.success).to.be.true
await refreshIndex()
const pages = await graphqlRequest(searchQuery(), authToken).expect(200)
expect(pages.body.data.search.pageInfo.totalCount).to.eql(0)
})
@ -1283,8 +1202,6 @@ describe('Article API', () => {
).expect(200)
expect(res.body.data.bulkAction.success).to.be.true
await refreshIndex()
const pages = await graphqlRequest(
searchQuery('in:all'),
authToken
@ -1315,28 +1232,20 @@ describe('Article API', () => {
let articleId = ''
before(async () => {
const page: Page = {
id: '',
hash: '',
userId: user.id,
pageType: PageType.Article,
const itemToSave: DeepPartial<LibraryItem> = {
user,
title: 'test setFavoriteArticle',
content: '',
slug: '',
createdAt: new Date(),
updatedAt: new Date(),
readingProgressPercent: 0,
readingProgressAnchorIndex: 0,
url: 'https://test.omnivore.app/setFavoriteArticle',
savedAt: new Date(),
state: ArticleSavingRequestStatus.Succeeded,
readableContent: '<p>test</p>',
originalUrl: `https://blog.omnivore.app/p/setFavoriteArticle`,
}
articleId = (await createPage(page, ctx))!
const item = await createLibraryItem(itemToSave, user.id)
articleId = item.id
})
after(async () => {
// Delete the page
await deletePagesByParam({ userId: user.id }, ctx)
await deleteLibraryItemById(articleId, user.id)
})
it('favorites the article', async () => {
@ -1352,8 +1261,8 @@ describe('Article API', () => {
res.body.data.setFavoriteArticle.favoriteArticle.labels[0].name
).to.eq('Favorites')
const page = await getPageById(articleId)
expect(page?.labels?.map((l) => l.name)).to.eql(['Favorites'])
const item = await findLibraryItemById(articleId, user.id)
expect(item?.labels?.map((l) => l.name)).to.eql(['Favorites'])
})
})
})

View file

@ -1,17 +1,13 @@
import { expect } from 'chai'
import 'mocha'
import sinon from 'sinon'
import { createPubSubClient } from '../../src/pubsub'
import { deletePagesByParam, getPageByParam } from '../../src/elastic/pages'
import {
ArticleSavingRequestStatus,
PageContext,
} from '../../src/elastic/types'
import { User } from '../../src/entity/user'
import {
ArticleSavingRequestErrorCode,
ArticleSavingRequestStatus,
CreateArticleSavingRequestErrorCode,
} from '../../src/generated/graphql'
import { findLibraryItemByUrl } from '../../src/services/library_item'
import * as createTask from '../../src/utils/createTask'
import { createTestUser, deleteTestUser } from '../db'
import { graphqlRequest, request } from '../util'
@ -62,7 +58,6 @@ const createArticleSavingRequestMutation = (url: string) => `
describe('ArticleSavingRequest API', () => {
let authToken: string
let user: User
let ctx: PageContext
before(async () => {
// create test user and login
@ -73,17 +68,11 @@ describe('ArticleSavingRequest API', () => {
authToken = res.body.authToken
ctx = {
pubsub: createPubSubClient(),
refresh: true,
uid: user.id,
}
sinon.replace(createTask, 'enqueueParseRequest', sinon.fake.resolves(''))
})
after(async () => {
// clean up
await deletePagesByParam({ userId: user.id }, ctx)
await deleteTestUser(user.id)
sinon.restore()
})
@ -100,15 +89,15 @@ describe('ArticleSavingRequest API', () => {
).to.eql(ArticleSavingRequestStatus.Processing)
})
it('creates a page in elastic', async () => {
it('creates a library item in db', async () => {
const url = 'https://blog.omnivore.app/1'
await graphqlRequest(
createArticleSavingRequestMutation('https://blog.omnivore.app/1'),
authToken
).expect(200)
const page = await getPageByParam({ url })
expect(page?.content).to.eql('Your link is being saved...')
const item = await findLibraryItemByUrl(url, user.id)
expect(item?.readableContent).to.eql('Your link is being saved...')
})
it('returns an error if the url is invalid', async () => {

View file

@ -1,6 +1,6 @@
import { createTestUser, deleteTestUser } from '../db'
import {
createTestElasticPage,
createTestLibraryItem,
generateFakeUuid,
graphqlRequest,
request,
@ -11,8 +11,7 @@ import 'mocha'
import { User } from '../../src/entity/user'
import chaiString from 'chai-string'
import { createPubSubClient } from '../../src/pubsub'
import { HighlightType, PageContext } from '../../src/elastic/types'
import { deletePage, updatePage } from '../../src/elastic/pages'
import { updateLibraryItem } from '../../src/services/library_item'
chai.use(chaiString)
@ -143,7 +142,6 @@ describe('Highlights API', () => {
let authToken: string
let user: User
let pageId: string
let ctx: PageContext
before(async () => {
// create test user and login
@ -153,15 +151,11 @@ describe('Highlights API', () => {
.send({ fakeEmail: user.email })
authToken = res.body.authToken
pageId = (await createTestElasticPage(user.id)).id
ctx = { pubsub: createPubSubClient(), uid: user.id, refresh: true }
pageId = (await createTestLibraryItem(user.id)).id
})
after(async () => {
await deleteTestUser(user.id)
if (pageId) {
await deletePage(pageId, ctx)
}
})
context('createHighlightMutation', () => {
@ -256,7 +250,7 @@ describe('Highlights API', () => {
before(async () => {
// create test highlight
highlightId = generateFakeUuid()
await updatePage(
await updateLibraryItem(
pageId,
{
highlights: [
@ -264,16 +258,13 @@ describe('Highlights API', () => {
id: highlightId,
shortId: '_short_id_3',
annotation: '',
userId: user.id,
patch: '',
quote: '',
createdAt: new Date(),
updatedAt: new Date(),
type: HighlightType.Highlight,
user,
},
],
},
ctx
user.id
)
})

View file

@ -1,21 +1,19 @@
import { expect } from 'chai'
import 'mocha'
import { createPubSubClient } from '../../src/pubsub'
import { refreshIndex } from '../../src/elastic'
import {
addHighlightToPage,
getHighlightById,
} from '../../src/elastic/highlights'
import { deletePage, getPageById } from '../../src/elastic/pages'
import {
Highlight,
HighlightType,
Page,
PageContext,
} from '../../src/elastic/types'
import { DeepPartial } from 'typeorm'
import { Highlight } from '../../src/entity/highlight'
import { Label } from '../../src/entity/label'
import { LibraryItem } from '../../src/entity/library_item'
import { User } from '../../src/entity/user'
import { getRepository } from '../../src/repository'
import {
createHighlight,
findHighlightById,
} from '../../src/services/highlights'
import {
deleteLibraryItemById,
findLibraryItemById,
} from '../../src/services/library_item'
import {
createTestLabel,
createTestUser,
@ -23,7 +21,7 @@ import {
deleteTestUser,
} from '../db'
import {
createTestElasticPage,
createTestLibraryItem,
generateFakeUuid,
graphqlRequest,
request,
@ -32,7 +30,6 @@ import {
describe('Labels API', () => {
let user: User
let authToken: string
let ctx: PageContext
before(async () => {
// create test user and login
@ -41,11 +38,6 @@ describe('Labels API', () => {
.post('/local/debug/fake-user-login')
.send({ fakeEmail: user.email })
authToken = res.body.authToken
ctx = {
pubsub: createPubSubClient(),
refresh: true,
uid: user.id,
}
})
after(async () => {
@ -250,62 +242,57 @@ describe('Labels API', () => {
})
context('when a page has this label', () => {
let page: Page
let item: LibraryItem
before(async () => {
toDeleteLabel = await createTestLabel(user, 'page label', '#ffffff')
labelId = toDeleteLabel.id
page = await createTestElasticPage(user.id, [toDeleteLabel])
item = await createTestLibraryItem(user.id, [toDeleteLabel])
})
after(async () => {
await deletePage(page.id, ctx)
await deleteLibraryItemById(item.id)
})
it('should update page', async () => {
await graphqlRequest(query, authToken).expect(200)
await refreshIndex()
const updatedPage = await getPageById(page.id)
expect(updatedPage?.labels).not.deep.include(toDeleteLabel)
const updatedItem = await findLibraryItemById(item.id, user.id)
expect(updatedItem?.labels).not.deep.include(toDeleteLabel)
})
})
context('when a highlight has this label', () => {
const highlightId = generateFakeUuid()
let page: Page
let item: LibraryItem
before(async () => {
page = await createTestElasticPage(user.id)
item = await createTestLibraryItem(user.id)
toDeleteLabel = await createTestLabel(
user,
'highlight label',
'#ffffff'
)
labelId = toDeleteLabel.id
const highlight: Highlight = {
const highlight: DeepPartial<Highlight> = {
id: highlightId,
patch: 'test patch',
quote: 'test quote',
shortId: 'test shortId',
userId: user.id,
createdAt: new Date(),
labels: [toDeleteLabel],
updatedAt: new Date(),
type: HighlightType.Highlight,
user,
}
await addHighlightToPage(page.id, highlight, ctx)
await createHighlight(highlight, item.id, user.id)
})
after(async () => {
await deletePage(page.id, ctx)
await deleteLibraryItemById(item.id)
})
it('should update highlight', async () => {
await graphqlRequest(query, authToken).expect(200)
await refreshIndex()
const updatedHighlight = await getHighlightById(highlightId)
const updatedHighlight = await findHighlightById(highlightId, user.id)
expect(updatedHighlight?.labels).not.deep.include(toDeleteLabel)
})
})
@ -340,17 +327,17 @@ describe('Labels API', () => {
describe('Set labels', () => {
let query: string
let pageId: string
let itemId: string
let labelIds: string[] = []
let labels: Label[]
let page: Page
let item: LibraryItem
before(async () => {
// create testing labels
const label1 = await createTestLabel(user, 'label_1', '#ffffff')
const label2 = await createTestLabel(user, 'label_2', '#eeeeee')
labels = [label1, label2]
page = await createTestElasticPage(user.id)
item = await createTestLibraryItem(user.id)
})
after(async () => {
@ -359,7 +346,7 @@ describe('Labels API', () => {
user.id,
labels.map((l) => l.id)
)
await deletePage(page.id, ctx)
await deleteLibraryItemById(item.id)
})
beforeEach(() => {
@ -367,7 +354,7 @@ describe('Labels API', () => {
mutation {
setLabels(
input: {
pageId: "${pageId}",
pageId: "${itemId}",
labelIds: [
"${labelIds[0]}",
"${labelIds[1]}"
@ -390,20 +377,20 @@ describe('Labels API', () => {
context('when labels exists', () => {
before(() => {
pageId = page.id
itemId = item.id
labelIds = [labels[0].id, labels[1].id]
})
it('should set labels', async () => {
await graphqlRequest(query, authToken).expect(200)
const page = await getPageById(pageId)
const page = await findLibraryItemById(itemId, user.id)
expect(page?.labels?.map((l) => l.id)).to.eql(labelIds)
})
})
context('when labels not exist', () => {
before(() => {
pageId = page.id
itemId = item.id
labelIds = [generateFakeUuid(), generateFakeUuid()]
})
@ -413,9 +400,9 @@ describe('Labels API', () => {
})
})
context('when page not exist', () => {
context('when item not exist', () => {
before(() => {
pageId = generateFakeUuid()
itemId = generateFakeUuid()
labelIds = [labels[0].id, labels[1].id]
})
@ -504,22 +491,22 @@ describe('Labels API', () => {
expect(updatedLabel?.color).to.eql(color)
})
context('when a page has the label', () => {
let page: Page
context('when an item has the label', () => {
let item: LibraryItem
before(async () => {
page = await createTestElasticPage(user.id, [toUpdateLabel])
item = await createTestLibraryItem(user.id, [toUpdateLabel])
})
after(async () => {
await deletePage(page.id, ctx)
await deleteLibraryItemById(item.id)
})
it('should update the page with the label', async () => {
it('should update the item with the label', async () => {
await graphqlRequest(query, authToken).expect(200)
const updatedPage = await getPageById(page.id)
const updatedLabel = updatedPage?.labels?.filter(
const updatedItem = await findLibraryItemById(item.id, user.id)
const updatedLabel = updatedItem?.labels?.filter(
(l) => l.id === labelId
)?.[0]
@ -546,14 +533,14 @@ describe('Labels API', () => {
let highlightId: string
let labelIds: string[] = []
let labels: Label[]
let page: Page
let item: LibraryItem
before(async () => {
// create testing labels
const label1 = await createTestLabel(user, 'label_1', '#ffffff')
const label2 = await createTestLabel(user, 'label_2', '#eeeeee')
labels = [label1, label2]
page = await createTestElasticPage(user.id)
item = await createTestLibraryItem(user.id)
})
after(async () => {
@ -562,7 +549,7 @@ describe('Labels API', () => {
user.id,
labels.map((l) => l.id)
)
await deletePage(page.id, ctx)
await deleteLibraryItemById(item.id)
})
beforeEach(() => {
@ -594,17 +581,14 @@ describe('Labels API', () => {
context('when labels exists', () => {
before(async () => {
highlightId = generateFakeUuid()
const highlight: Highlight = {
createdAt: new Date(),
const highlight: DeepPartial<Highlight> = {
id: highlightId,
patch: 'test patch',
quote: 'test quote',
shortId: 'test shortId',
userId: user.id,
updatedAt: new Date(),
type: HighlightType.Highlight,
user,
}
await addHighlightToPage(page.id, highlight, ctx)
await createHighlight(highlight, item.id, user.id)
labelIds = [labels[0].id, labels[1].id]
})
@ -619,17 +603,14 @@ describe('Labels API', () => {
context('when labels not exist', () => {
before(async () => {
highlightId = generateFakeUuid()
const highlight: Highlight = {
createdAt: new Date(),
const highlight: DeepPartial<Highlight> = {
id: highlightId,
patch: 'test patch',
quote: 'test quote',
shortId: 'test shortId',
userId: user.id,
updatedAt: new Date(),
type: HighlightType.Highlight,
user,
}
await addHighlightToPage(page.id, highlight, ctx)
await createHighlight(highlight, item.id, user.id)
labelIds = [generateFakeUuid(), generateFakeUuid()]
})

View file

@ -1,7 +1,7 @@
import { expect } from 'chai'
import 'mocha'
import { getPageByParam } from '../../src/elastic/pages'
import { User } from '../../src/entity/user'
import { findLibraryItemById } from '../../src/services/library_item'
import { createTestUser, deleteTestUser } from '../db'
import { graphqlRequest, request } from '../util'
@ -48,14 +48,14 @@ describe('PopularReads API', () => {
).expect(200)
expect(res.body.data.addPopularRead.pageId).to.be
const page = await getPageByParam({
userId: user.id,
_id: res.body.data.addPopularRead.pageId,
})
expect(page?.url).to.eq(
const item = await findLibraryItemById(
res.body.data.addPopularRead.pageId,
user.id
)
expect(item?.originalUrl).to.eq(
'https://blog.omnivore.app/p/getting-started-with-omnivore'
)
expect(page?.wordsCount).to.eq(1155)
expect(item?.wordCount).to.eq(1155)
})
it('responds status code 500 when invalid user', async () => {

View file

@ -1,7 +1,5 @@
import { expect } from 'chai'
import 'mocha'
import { createPubSubClient } from '../../src/pubsub'
import { PageContext } from '../../src/elastic/types'
import { SearchHistory } from '../../src/entity/search_history'
import { User } from '../../src/entity/user'
import { getRepository } from '../../src/repository'
@ -11,7 +9,6 @@ import { graphqlRequest, request } from '../util'
describe('recent_searches resolver', () => {
let user: User
let authToken: string
let ctx: PageContext
before(async () => {
// create fake user and login
@ -20,11 +17,6 @@ describe('recent_searches resolver', () => {
.post('/local/debug/fake-user-login')
.send({ fakeEmail: user.email })
authToken = res.body.authToken
ctx = {
pubsub: createPubSubClient(),
refresh: true,
uid: user.id,
}
})
after(async () => {

View file

@ -1,16 +1,7 @@
import {
createTestElasticPage,
generateFakeUuid,
graphqlRequest,
request,
} from '../util'
import {
createTestReminder,
createTestUser,
deleteTestUser,
getReminder,
} from '../db'
import { expect } from 'chai'
import { DateTime } from 'luxon'
import 'mocha'
import { LibraryItem } from '../../src/entity/library_item'
import { Reminder } from '../../src/entity/reminder'
import { User } from '../../src/entity/user'
import {
@ -18,13 +9,22 @@ import {
ReminderErrorCode,
UpdateReminderErrorCode,
} from '../../src/generated/graphql'
import { DateTime } from 'luxon'
import 'mocha'
import { Page } from '../../src/elastic/types'
import {
createTestReminder,
createTestUser,
deleteTestUser,
getReminder,
} from '../db'
import {
createTestLibraryItem,
generateFakeUuid,
graphqlRequest,
request,
} from '../util'
xdescribe('Reminders API', () => {
let authToken: string
let page: Page
let item: LibraryItem
let reminder: Reminder
let user: User
@ -38,8 +38,8 @@ xdescribe('Reminders API', () => {
authToken = res.body.authToken
// create page, link and reminders test data
page = await createTestElasticPage(user.id)
reminder = await createTestReminder(user, page.id)
item = await createTestLibraryItem(user.id)
reminder = await createTestReminder(user, item.id)
})
after(async () => {
@ -72,7 +72,7 @@ xdescribe('Reminders API', () => {
context('when reminder is found', () => {
before(() => {
// existing page id
linkId = page.id
linkId = item.id
})
it('responds with the reminder', async () => {
@ -145,7 +145,7 @@ xdescribe('Reminders API', () => {
context('when link is valid', () => {
before(() => {
linkId = page.id
linkId = item.id
})
it('responds with status code 200', async () => {

View file

@ -1,16 +1,17 @@
import { expect } from 'chai'
import { Page } from '../../src/elastic/types'
import 'mocha'
import { LibraryItem } from '../../src/entity/library_item'
import { ContentDisplayReport } from '../../src/entity/reports/content_display_report'
import { User } from '../../src/entity/user'
import { ReportType } from '../../src/generated/graphql'
import { getRepository } from '../../src/repository'
import { createTestUser, deleteTestUser } from '../db'
import { createTestElasticPage, graphqlRequest, request } from '../util'
import { createTestLibraryItem, graphqlRequest, request } from '../util'
describe('Report API', () => {
let user: User
let authToken: string
let page: Page
let item: LibraryItem
before(async () => {
// create test user and login
@ -22,7 +23,7 @@ describe('Report API', () => {
authToken = res.body.authToken
// create a page
page = await createTestElasticPage(user.id)
item = await createTestLibraryItem(user.id)
})
after(async () => {
@ -54,18 +55,17 @@ describe('Report API', () => {
context('when page exists and report is content display', () => {
before(() => {
pageId = page.id
pageId = item.id
reportTypes = [ReportType.ContentDisplay]
})
it('should report an item', async () => {
await graphqlRequest(query, authToken).expect(200)
expect(
await getRepository(ContentDisplayReport).findBy({
elasticPageId: pageId,
})
).to.exist
const report = await getRepository(ContentDisplayReport).findOneBy({
libraryItemId: item.id,
})
expect(report).to.exist
})
})
})

View file

@ -1,14 +1,14 @@
import { expect } from 'chai'
import 'mocha'
import { Page } from '../../src/elastic/types'
import { LibraryItem } from '../../src/entity/library_item'
import { User } from '../../src/entity/user'
import { createTestUser, deleteTestUser } from '../db'
import { createTestElasticPage, graphqlRequest, request } from '../util'
import { createTestLibraryItem, graphqlRequest, request } from '../util'
describe('Update API', () => {
let user: User
let authToken: string
let page: Page
let item: LibraryItem
before(async () => {
// create test user and login
@ -18,7 +18,7 @@ describe('Update API', () => {
.send({ fakeEmail: user.email })
authToken = res.body.authToken
page = await createTestElasticPage(user.id)
item = await createTestLibraryItem(user.id)
})
after(async () => {
@ -37,7 +37,7 @@ describe('Update API', () => {
mutation {
updatePage(
input: {
pageId: "${page.id}"
pageId: "${item.id}"
title: "${title}"
description: "${description}"
previewImage: "${previewImage}"

View file

@ -1,13 +1,14 @@
import { createTestUser, deleteTestUser } from '../db'
import { generateFakeUuid, graphqlRequest, request } from '../util'
import * as chai from 'chai'
import { expect } from 'chai'
import chaiString from 'chai-string'
import 'mocha'
import { User } from '../../src/entity/user'
import chaiString from 'chai-string'
import { PageContext } from '../../src/elastic/types'
import { createPubSubClient } from '../../src/pubsub'
import { deletePage, getPageById } from '../../src/elastic/pages'
import {
deleteLibraryItemById,
findLibraryItemById,
} from '../../src/services/library_item'
import { createTestUser, deleteTestUser } from '../db'
import { generateFakeUuid, graphqlRequest, request } from '../util'
chai.use(chaiString)
@ -48,7 +49,6 @@ const uploadFileRequest = async (
describe('uploadFileRequest API', () => {
let authToken: string
let user: User
let ctx: PageContext
before(async () => {
// create test user and login
@ -58,12 +58,6 @@ describe('uploadFileRequest API', () => {
.send({ fakeEmail: user.email })
authToken = res.body.authToken
ctx = {
pubsub: createPubSubClient(),
refresh: true,
uid: user.id,
}
})
after(async () => {
@ -75,7 +69,7 @@ describe('uploadFileRequest API', () => {
const clientRequestId = generateFakeUuid()
after(async () => {
await deletePage(clientRequestId, ctx)
await deleteLibraryItemById(clientRequestId)
})
xit('should create an article if create article is true', async () => {
@ -88,8 +82,8 @@ describe('uploadFileRequest API', () => {
expect(res.body.data.uploadFileRequest.createdPageId).to.eql(
clientRequestId
)
const page = await getPageById(clientRequestId)
expect(page).to.be
const item = await findLibraryItemById(clientRequestId, user.id)
expect(item).to.be
})
xit('should not save a file:// URL', async () => {
@ -102,8 +96,8 @@ describe('uploadFileRequest API', () => {
expect(res.body.data.uploadFileRequest.createdPageId).to.eql(
clientRequestId
)
const page = await getPageById(clientRequestId)
expect(page?.url).to.startWith('https://')
const item = await findLibraryItemById(clientRequestId, user.id)
expect(item?.originalUrl).to.startWith('https://')
})
})
})

View file

@ -1,172 +0,0 @@
import { expect } from 'chai'
import 'mocha'
import { Highlight } from '../../src/entity/highlight'
import { Link } from '../../src/entity/link'
import { Page } from '../../src/entity/page'
import { User } from '../../src/entity/user'
import { SharedArticleErrorCode } from '../../src/generated/graphql'
import { getRepository } from '../../src/repository'
import {
createTestLink,
createTestPage,
createTestUser,
deleteTestUser,
} from '../db'
import { graphqlRequest, request } from '../util'
xdescribe('User feed article API', () => {
const existingUsername = 'fakeUser'
let user: User
let authToken: string
let page: Page
let link: Link
let highlight: Highlight
before(async () => {
// create test user and login
user = await createTestUser(existingUsername)
const res = await request
.post('/local/debug/fake-user-login')
.send({ fakeEmail: user.email })
authToken = res.body.authToken
page = await createTestPage()
link = await createTestLink(user, page)
highlight = await getRepository(Highlight).save({
page: page,
text: 'test',
user: user,
shortId: 'test',
patch: 'test',
quote: 'test',
})
})
after(async () => {
// clean up
await deleteTestUser(user.id)
})
describe('get shared article', () => {
let username = 'someUser'
let slug = 'Some slug'
let selectedHighlightId = 'some-highlight-id'
let query: string
beforeEach(() => {
query = `
query {
sharedArticle(
username: "${username}"
slug: "${slug}"
selectedHighlightId: "${selectedHighlightId}"
) {
... on SharedArticleSuccess {
article {
id
}
}
... on SharedArticleError {
errorCodes
}
}
}
`
})
context('when user not exists', () => {
before(() => {
username = 'notExists'
})
it('should responds NotFound', async () => {
const response = await graphqlRequest(query, authToken).expect(200)
expect(response.body.data.sharedArticle.errorCodes).to.eql([
SharedArticleErrorCode.NotFound,
])
})
})
context('when article not exists', () => {
before(() => {
username = existingUsername
slug = 'notExists'
})
it('should responds NotFound', async () => {
const response = await graphqlRequest(query, authToken).expect(200)
expect(response.body.data.sharedArticle.errorCodes).to.eql([
SharedArticleErrorCode.NotFound,
])
})
})
context('when article exists but not shared', () => {
before(() => {
username = existingUsername
slug = link.slug
})
it('should responds NotFound', async () => {
const response = await graphqlRequest(query, authToken).expect(200)
expect(response.body.data.sharedArticle.errorCodes).to.eql([
SharedArticleErrorCode.NotFound,
])
})
})
context('when article exists but highlight not exists', () => {
before(() => {
username = existingUsername
slug = link.slug
selectedHighlightId = 'NotExists'
})
it('should responds NotFound', async () => {
const response = await graphqlRequest(query, authToken).expect(200)
expect(response.body.data.sharedArticle.errorCodes).to.eql([
SharedArticleErrorCode.NotFound,
])
})
})
context('when highlight exists but not shared', () => {
before(() => {
username = existingUsername
slug = link.slug
selectedHighlightId = highlight.id || 'some-highlight-id'
})
it('should responds NotFound', async () => {
const response = await graphqlRequest(query, authToken).expect(200)
expect(response.body.data.sharedArticle.errorCodes).to.eql([
SharedArticleErrorCode.NotFound,
])
})
})
context('when article exists and shared', () => {
before(async () => {
username = existingUsername
slug = link.slug
selectedHighlightId = ''
await getRepository(Link).update(link.id, {
sharedAt: new Date(),
})
})
after(async () => {
await getRepository(Link).update(link.id, {
sharedAt: null,
})
})
// TODO: add test for shared article when shared article api is ready
xit('should responds SharedArticleSuccess', async () => {
const response = await graphqlRequest(query, authToken).expect(200)
expect(response.body.data.sharedArticle.article.id).to.eql(page.id)
})
})
})
})

View file

@ -3,11 +3,11 @@ import chai, { expect } from 'chai'
import sinon from 'sinon'
import sinonChai from 'sinon-chai'
import supertest from 'supertest'
import { searchLibraryItems } from '../../src/elastic/pages'
import { StatusType, User } from '../../src/entity/user'
import { getRepository } from '../../src/repository'
import { AuthProvider } from '../../src/routers/auth/auth_types'
import { createPendingUserToken } from '../../src/routers/auth/jwt_helpers'
import { searchLibraryItems } from '../../src/services/library_item'
import {
comparePassword,
generateVerificationToken,
@ -604,11 +604,8 @@ describe('auth router', () => {
pendingUserToken!,
'web'
).expect(200)
const user = await getRepository(User).findOneBy({ name })
const [popularReads, count] = (await searchLibraryItems(
{},
user?.id!
)) || [[], 0]
const user = await getRepository(User).findOneByOrFail({ name })
const { count } = await searchLibraryItems({}, user.id)
expect(count).to.eql(3)
})
@ -628,11 +625,8 @@ describe('auth router', () => {
pendingUserToken!,
'ios'
).expect(200)
const user = await getRepository(User).findOneBy({ name })
const [popularReads, count] = (await searchLibraryItems(
{},
user?.id!
)) || [[], 0]
const user = await getRepository(User).findOneByOrFail({ name })
const { count } = await searchLibraryItems({}, user.id)
expect(count).to.eql(4)
})

View file

@ -4,27 +4,19 @@ import { DateTime } from 'luxon'
import 'mocha'
import nock from 'nock'
import sinon from 'sinon'
import {
createPubSubClient,
PubSubRequestBody,
} from '../../src/pubsub'
import { addHighlightToPage } from '../../src/elastic/highlights'
import { deletePage } from '../../src/elastic/pages'
import {
Highlight,
HighlightType,
Page,
PageContext,
} from '../../src/elastic/types'
import { Highlight } from '../../src/entity/highlight'
import { Integration, IntegrationType } from '../../src/entity/integration'
import { LibraryItem } from '../../src/entity/library_item'
import { User } from '../../src/entity/user'
import { env } from '../../src/env'
import { PubSubRequestBody } from '../../src/pubsub'
import { getRepository } from '../../src/repository'
import { getHighlightUrl } from '../../src/services/highlights'
import { createHighlight, getHighlightUrl } from '../../src/services/highlights'
import { READWISE_API_URL } from '../../src/services/integrations/readwise'
import { deleteLibraryItemById } from '../../src/services/library_item'
import { createTestUser, deleteTestIntegrations, deleteTestUser } from '../db'
import { MockBucket } from '../mock_storage'
import { createTestElasticPage, request } from '../util'
import { createTestLibraryItem, request } from '../util'
describe('Integrations routers', () => {
const baseUrl = '/svc/pubsub/integrations'
@ -128,8 +120,7 @@ describe('Integrations routers', () => {
context('when integration is readwise and enabled', () => {
let integration: Integration
let ctx: PageContext
let page: Page
let item: LibraryItem
let highlight: Highlight
let highlightsData: string
@ -141,42 +132,37 @@ describe('Integrations routers', () => {
})
integrationName = integration.name
// create page
page = await createTestElasticPage(user.id)
ctx = {
uid: user.id,
pubsub: createPubSubClient(),
refresh: true,
}
item = await createTestLibraryItem(user.id)
// create highlight
const highlightPositionPercent = 25
highlight = {
createdAt: new Date(),
id: 'test id',
patch: 'test patch',
quote: 'test quote',
shortId: 'test shortId',
updatedAt: new Date(),
userId: user.id,
highlightPositionPercent,
type: HighlightType.Highlight,
}
await addHighlightToPage(page.id, highlight, ctx)
highlight = await createHighlight(
{
patch: 'test patch',
quote: 'test quote',
shortId: 'test shortId',
highlightPositionPercent,
user,
},
item.id,
user.id
)
// create highlights data for integration request
highlightsData = JSON.stringify({
highlights: [
{
text: highlight.quote,
title: page.title,
author: page.author,
highlight_url: getHighlightUrl(page.slug, highlight.id),
title: item.title,
author: item.author,
highlight_url: getHighlightUrl(item.slug, highlight.id),
highlighted_at: highlight.createdAt.toISOString(),
category: 'articles',
image_url: page.image,
image_url: item.thumbnail,
// location: highlightPositionPercent,
location_type: 'order',
note: highlight.annotation,
source_type: 'omnivore',
source_url: page.url,
source_url: item.originalUrl,
},
],
})
@ -184,7 +170,7 @@ describe('Integrations routers', () => {
after(async () => {
await deleteTestIntegrations(user.id, [integration.id])
await deletePage(page.id, ctx)
await deleteLibraryItemById(item.id)
})
context('when action is sync_updated', () => {
@ -200,7 +186,7 @@ describe('Integrations routers', () => {
JSON.stringify({
userId: user.id,
type: 'page',
id: page.id,
id: item.id,
})
).toString('base64'),
publishTime: new Date().toISOString(),
@ -267,7 +253,7 @@ describe('Integrations routers', () => {
JSON.stringify({
userId: user.id,
type: 'highlight',
articleId: page.id,
articleId: item.id,
})
).toString('base64'),
publishTime: new Date().toISOString(),

View file

@ -1,14 +1,14 @@
import { expect } from 'chai'
import * as jwt from 'jsonwebtoken'
import 'mocha'
import { User } from '../../src/entity/user'
import { findLibraryItemById } from '../../src/services/library_item'
import {
createTestNewsletterEmail,
createTestUser,
deleteTestUser,
} from '../db'
import { request } from '../util'
import { User } from '../../src/entity/user'
import 'mocha'
import * as jwt from 'jsonwebtoken'
import { expect } from 'chai'
import { getPageById } from '../../src/elastic/pages'
describe('PDF attachments Router', () => {
const newsletterEmail = 'fakeEmail@omnivore.app'
@ -75,9 +75,9 @@ describe('PDF attachments Router', () => {
.expect(200)
expect(res2.body.id).to.be.a('string')
const link = await getPageById(res2.body.id)
const item = await findLibraryItemById(res2.body.id, user.id)
expect(link).to.exist
expect(item).to.exist
})
})
})

View file

@ -1,54 +1,52 @@
import {
createTestLink,
createTestPage,
createTestReminder,
createTestUser,
deleteTestUser,
getReminder,
} from '../db'
import { request } from '../util'
import { User } from '../../src/entity/user'
import { Reminder } from '../../src/entity/reminder'
import { expect } from 'chai'
import 'mocha'
// import {
// createTestReminder,
// createTestUser,
// deleteTestUser,
// getReminder,
// } from '../db'
// import { request } from '../util'
// import { User } from '../../src/entity/user'
// import { Reminder } from '../../src/entity/reminder'
// import { expect } from 'chai'
// import 'mocha'
xdescribe('Reminders Router', () => {
let authToken: string
let user: User
let reminder: Reminder
// xdescribe('Reminders Router', () => {
// let authToken: string
// let user: User
// let reminder: Reminder
before(async () => {
// create test user and login
user = await createTestUser('fakeUser')
const res = await request
.post('/local/debug/fake-user-login')
.send({ fakeEmail: user.email })
// before(async () => {
// // create test user and login
// user = await createTestUser('fakeUser')
// const res = await request
// .post('/local/debug/fake-user-login')
// .send({ fakeEmail: user.email })
authToken = res.body.authToken
// authToken = res.body.authToken
const page = await createTestPage()
const link = await createTestLink(user, page)
reminder = await createTestReminder(user, link.id)
})
// const page = await createTestPage()
// const link = await createTestLink(user, page)
// reminder = await createTestReminder(user, link.id)
// })
after(async () => {
// clean up
await deleteTestUser(user.id)
})
// after(async () => {
// // clean up
// await deleteTestUser(user.id)
// })
describe('trigger reminders', () => {
it('should trigger reminders and update status to Complete', async () => {
await request
.post('/svc/reminders/trigger')
.send({
userId: user.id,
scheduleTime: reminder.remindAt,
})
.set('Authorization', `${authToken}`)
.expect(200)
// describe('trigger reminders', () => {
// it('should trigger reminders and update status to Complete', async () => {
// await request
// .post('/svc/reminders/trigger')
// .send({
// userId: user.id,
// scheduleTime: reminder.remindAt,
// })
// .set('Authorization', `${authToken}`)
// .expect(200)
const completed = await getReminder(reminder.id)
expect(completed?.status).to.eql('COMPLETED')
})
})
})
// const completed = await getReminder(reminder.id)
// expect(completed?.status).to.eql('COMPLETED')
// })
// })
// })

View file

@ -1,24 +1,24 @@
import chai, { expect } from 'chai'
import 'mocha'
import sinonChai from 'sinon-chai'
import { Page } from '../../src/elastic/types'
import { LibraryItem } from '../../src/entity/library_item'
import { ContentDisplayReport } from '../../src/entity/reports/content_display_report'
import { User } from '../../src/entity/user'
import { ReportType } from '../../src/generated/graphql'
import { getRepository } from '../../src/repository'
import { authTrx, getRepository } from '../../src/repository'
import { saveContentDisplayReport } from '../../src/services/reports'
import { createTestUser, deleteTestUser } from '../db'
import { createTestElasticPage } from '../util'
import { createTestLibraryItem } from '../util'
chai.use(sinonChai)
describe('saveContentDisplayReport', () => {
let user: User
let page: Page
let item: LibraryItem
before(async () => {
user = await createTestUser('fakeContentUser')
page = await createTestElasticPage(user.id)
item = await createTestLibraryItem(user.id)
})
after(async () => {
@ -28,14 +28,14 @@ describe('saveContentDisplayReport', () => {
it('creates a report', async () => {
const result = await saveContentDisplayReport(user.id, {
itemUrl: 'https://fake.url.com',
pageId: page.id,
pageId: item.id,
reportComment: 'report comment',
reportTypes: [ReportType.ContentDisplay],
})
expect(result).to.eql(true)
const saved = await getRepository(ContentDisplayReport).findOneBy({
user: { id: user.id },
elasticPageId: page.id,
libraryItemId: item.id,
})
expect(saved?.reportComment).to.eql('report comment')

View file

@ -5,10 +5,6 @@ import sinon from 'sinon'
import sinonChai from 'sinon-chai'
import { StatusType, User } from '../../src/entity/user'
import { getRepository } from '../../src/repository'
import {
getUserFollowers,
getUserFollowing,
} from '../../src/services/followers'
import { createGroup } from '../../src/services/groups'
import * as util from '../../src/utils/sendEmail'
import {
@ -40,39 +36,39 @@ describe('create user', () => {
})
context('create a user with an invite', () => {
it('follows the other user in the group', async () => {
after(async () => {
const testUser = await getRepository(User).findOneBy({
name: 'testuser',
})
await deleteTestUser(testUser!.id)
const testOwner = await getRepository(User).findOneBy({
name: 'testowner',
})
await deleteTestUser(testOwner!.id)
})
// it('follows the other user in the group', async () => {
// after(async () => {
// const testUser = await getRepository(User).findOneBy({
// name: 'testuser',
// })
// await deleteTestUser(testUser!.id)
// const testOwner = await getRepository(User).findOneBy({
// name: 'testowner',
// })
// await deleteTestUser(testOwner!.id)
// })
const testOwner = 'testowner'
const testUser = 'testuser'
// const testOwner = 'testowner'
// const testUser = 'testuser'
const adminUser = await createTestUser(testOwner)
const admninIds = [adminUser.id]
const [, invite] = await createGroup({
admin: adminUser,
name: 'testgroup',
})
const user = await createTestUser(testUser, invite.code)
const userIds = [user.id]
// const adminUser = await createTestUser(testOwner)
// const admninIds = [adminUser.id]
// const [, invite] = await createGroup({
// admin: adminUser,
// name: 'testgroup',
// })
// const user = await createTestUser(testUser, invite.code)
// const userIds = [user.id]
const userFollowers = await getUserFollowers(user)
const userFollowing = await getUserFollowing(user)
const adminUserFollowers = await getUserFollowers(adminUser)
const adminUserFollowing = await getUserFollowing(adminUser)
expect(userFollowers.map((u) => u.id)).to.eql(admninIds)
expect(userFollowing.map((u) => u.id)).to.eql(admninIds)
expect(adminUserFollowers.map((u) => u.id)).to.eql(userIds)
expect(adminUserFollowing.map((u) => u.id)).to.eql(userIds)
})
// const userFollowers = await getUserFollowers(user)
// const userFollowing = await getUserFollowing(user)
// const adminUserFollowers = await getUserFollowers(adminUser)
// const adminUserFollowing = await getUserFollowing(adminUser)
// expect(userFollowers.map((u) => u.id)).to.eql(admninIds)
// expect(userFollowing.map((u) => u.id)).to.eql(admninIds)
// expect(adminUserFollowers.map((u) => u.id)).to.eql(userIds)
// expect(adminUserFollowing.map((u) => u.id)).to.eql(userIds)
// })
it('creates profile when user exists but profile not', async () => {
after(async () => {

View file

@ -1,55 +0,0 @@
import { expect } from 'chai'
import 'mocha'
import { Label } from '../../src/entity/label'
import { Link } from '../../src/entity/link'
import { LinkLabel } from '../../src/entity/link_label'
import { User } from '../../src/entity/user'
import { getRepository } from '../../src/repository'
import { labelsLoader } from '../../src/services/labels'
import {
createTestLabel,
createTestLink,
createTestPage,
createTestUser,
deleteTestUser,
} from '../db'
describe('batch get labels from linkIds', () => {
let user: User
let labels: Label[] = []
let link: Link
before(async () => {
// create test user
user = await createTestUser('fakeUser')
// Create some test links
const page = await createTestPage()
link = await createTestLink(user, page)
for (let i = 0; i < 3; i++) {
// create testing labels
const label = await createTestLabel(user, `label_${i}`, '#d55757')
// set label to a link
await getRepository(LinkLabel).save({
link: link,
label: label,
})
labels.push(label)
}
})
after(async () => {
// clean up
await deleteTestUser(user.id)
})
it('should return a list of label from one link', async () => {
const result = await labelsLoader.load(link.id)
expect(result).length(3)
expect(result[0].id).to.eql(labels[0].id)
expect(result[1].id).to.eql(labels[1].id)
expect(result[2].id).to.eql(labels[2].id)
})
})

View file

@ -1,8 +1,8 @@
import { expect } from 'chai'
import 'mocha'
import nock from 'nock'
import { getPageByParam } from '../../src/elastic/pages'
import { User } from '../../src/entity/user'
import { findLibraryItemByUrl } from '../../src/services/library_item'
import { saveEmail } from '../../src/services/save_email'
import { createTestUser, deleteTestUser } from '../db'
@ -51,14 +51,11 @@ describe('saveEmail', () => {
})
expect(secondResult).to.not.be.undefined
const page = await getPageByParam({
userId: user.id,
url,
})
expect(page).to.exist
expect(page?.url).to.equal(url)
expect(page?.title).to.equal(title)
expect(page?.author).to.equal(author)
expect(page?.content).to.contain(fakeContent)
const item = await findLibraryItemByUrl(url, user.id)
expect(item).to.exist
expect(item?.originalUrl).to.equal(url)
expect(item?.title).to.equal(title)
expect(item?.author).to.equal(author)
expect(item?.readableContent).to.contain(fakeContent)
})
})

View file

@ -1,12 +1,12 @@
import { expect } from 'chai'
import 'mocha'
import nock from 'nock'
import { getPageByParam } from '../../src/elastic/pages'
import { NewsletterEmail } from '../../src/entity/newsletter_email'
import { ReceivedEmail } from '../../src/entity/received_email'
import { Subscription } from '../../src/entity/subscription'
import { User } from '../../src/entity/user'
import { getRepository } from '../../src/repository'
import { findLibraryItemByUrl } from '../../src/services/library_item'
import { createNewsletterEmail } from '../../src/services/newsletters'
import { saveNewsletter } from '../../src/services/save_newsletter_email'
import { createTestUser, deleteTestUser } from '../db'
@ -59,12 +59,12 @@ describe('saveNewsletterEmail', () => {
newsletterEmail
)
const page = await getPageByParam({ userId: user.id, url })
expect(page).to.exist
expect(page?.url).to.equal(url)
expect(page?.title).to.equal(title)
expect(page?.author).to.equal(author)
expect(page?.content).to.contain(fakeContent)
const item = await findLibraryItemByUrl(url, user.id)
expect(item).to.exist
expect(item?.originalUrl).to.equal(url)
expect(item?.title).to.equal(title)
expect(item?.author).to.equal(author)
expect(item?.readableContent).to.contain(fakeContent)
const subscriptions = await getRepository(Subscription).findBy({
newsletterEmail: { id: newsletterEmail.id },
@ -94,8 +94,8 @@ describe('saveNewsletterEmail', () => {
newsletterEmail
)
const page = await getPageByParam({ userId: user.id, url })
expect(page?.labels?.[0]).to.deep.include(newLabel)
const item = await findLibraryItemByUrl(url, user.id)
expect(item?.labels?.[0]).to.deep.include(newLabel)
})
it('does not create a subscription if no unsubscribe header', async () => {

View file

@ -1,10 +1,10 @@
import supertest from 'supertest'
import { DeepPartial } from 'typeorm'
import { v4 } from 'uuid'
import { createPage } from '../src/elastic/pages'
import { ArticleSavingRequestStatus, Label, Page } from '../src/elastic/types'
import { PageType } from '../src/generated/graphql'
import { createPubSubClient } from '../src/pubsub'
import { Label } from '../src/entity/label'
import { LibraryItem } from '../src/entity/library_item'
import { createApp } from '../src/server'
import { createLibraryItem } from '../src/services/library_item'
import { corsConfig } from '../src/utils/corsConfig'
const { app, apollo } = createApp()
@ -37,31 +37,18 @@ export const generateFakeUuid = () => {
return v4()
}
export const createTestElasticPage = async (
export const createTestLibraryItem = async (
userId: string,
labels?: Label[]
): Promise<Page> => {
const page: Page = {
id: '',
hash: 'test hash',
userId,
pageType: PageType.Article,
): Promise<LibraryItem> => {
const item: DeepPartial<LibraryItem> = {
user: { id: userId },
title: 'test title',
content: '<p>test content</p>',
createdAt: new Date(),
savedAt: new Date(),
url: 'https://blog.omnivore.app/test-url',
originalContent: '<p>test content</p>',
originalUrl: 'https://blog.omnivore.app/test-url',
slug: 'test-with-omnivore',
labels: labels,
readingProgressPercent: 0,
readingProgressAnchorIndex: 0,
state: ArticleSavingRequestStatus.Succeeded,
labels,
}
page.id = (await createPage(page, {
pubsub: createPubSubClient(),
refresh: true,
uid: userId,
}))!
return page
return createLibraryItem(item, userId)
}

View file

@ -1,19 +1,26 @@
import 'mocha'
import { expect } from 'chai'
import { contentReaderForPage } from '../../src/utils/uploads'
import { ContentReader, PageType } from '../../src/generated/graphql'
import 'mocha'
import { LibraryItemType } from '../../src/entity/library_item'
import { ContentReader } from '../../src/generated/graphql'
import { contentReaderForLibraryItem } from '../../src/utils/uploads'
describe('contentReaderForPage', () => {
it('returns web if there is no uploadFileId', () => {
const result = contentReaderForPage(PageType.Book, undefined)
const result = contentReaderForLibraryItem(LibraryItemType.Book, undefined)
expect(result).to.eq(ContentReader.Web)
})
it('returns Epub if there is an uploadFileId and type is book', () => {
const result = contentReaderForPage(PageType.Book, 'fakeUploadFileId')
const result = contentReaderForLibraryItem(
LibraryItemType.Book,
'fakeUploadFileId'
)
expect(result).to.eq(ContentReader.Epub)
})
it('returns PDF if there is an uploadFileId and type is File', () => {
const result = contentReaderForPage(PageType.File, 'fakeUploadFileId')
const result = contentReaderForLibraryItem(
LibraryItemType.File,
'fakeUploadFileId'
)
expect(result).to.eq(ContentReader.Pdf)
})
})