parent
aa662682f3
commit
1d3859a4e2
|
@ -10,6 +10,9 @@ import { getStatus, getStatusContext } from '../_api/statuses'
|
|||
import { emit } from '../_utils/eventBus'
|
||||
import { TIMELINE_BATCH_SIZE } from '../_static/timelines'
|
||||
import { timelineItemToSummary } from '../_utils/timelineItemToSummary'
|
||||
import uniqBy from 'lodash-es/uniqBy'
|
||||
|
||||
const byId = _ => _.id
|
||||
|
||||
async function storeFreshTimelineItemsInDatabase (instanceName, timelineName, items) {
|
||||
await database.insertTimelineItems(instanceName, timelineName, items)
|
||||
|
@ -70,7 +73,7 @@ export async function addTimelineItemSummaries (instanceName, timelineName, newS
|
|||
const oldSummaries = store.getForTimeline(instanceName, timelineName, 'timelineItemSummaries') || []
|
||||
const oldStale = store.getForTimeline(instanceName, timelineName, 'timelineItemSummariesAreStale')
|
||||
|
||||
const mergedSummaries = mergeArrays(oldSummaries, newSummaries, compareTimelineItemSummaries)
|
||||
const mergedSummaries = uniqBy(mergeArrays(oldSummaries, newSummaries, compareTimelineItemSummaries), byId)
|
||||
|
||||
if (!isEqual(oldSummaries, mergedSummaries)) {
|
||||
store.setForTimeline(instanceName, timelineName, { timelineItemSummaries: mergedSummaries })
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
import ListLazyItem from './ListLazyItem.html'
|
||||
import { listStore } from './listStore'
|
||||
import { getScrollContainer } from '../../_utils/scrollContainer'
|
||||
import { observe } from 'svelte-extras'
|
||||
|
||||
function getScrollTopOffset () {
|
||||
const style = getComputedStyle(document.documentElement)
|
||||
|
@ -30,11 +31,20 @@
|
|||
oncreate () {
|
||||
const { realm } = this.get()
|
||||
this.store.setCurrentRealm(realm)
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
this.observe('safeItems', safeItems => {
|
||||
if (new Set(safeItems).size !== safeItems.length) {
|
||||
console.error('list of items is not unique:', safeItems)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
ondestroy () {
|
||||
this.store.setCurrentRealm(null)
|
||||
},
|
||||
methods: {
|
||||
observe,
|
||||
itemInitialized () {
|
||||
let { initializedCount, length } = this.get()
|
||||
initializedCount++
|
||||
|
|
|
@ -3,9 +3,17 @@ import {
|
|||
getNthStatus,
|
||||
getNthStatusContent,
|
||||
getUrl,
|
||||
getNthReplyButton, getNthComposeReplyInput, sleep,
|
||||
getNthReplyButton,
|
||||
getNthComposeReplyInput,
|
||||
sleep,
|
||||
getAriaSetSize,
|
||||
getNthComposeReplyButton, goBack, goForward
|
||||
getNthComposeReplyButton,
|
||||
goBack,
|
||||
goForward,
|
||||
composeInput,
|
||||
composeButton,
|
||||
getNthStatusId,
|
||||
getStatusContents
|
||||
} from '../utils'
|
||||
import { postAs, postReplyAs } from '../serverActions'
|
||||
|
||||
|
@ -106,3 +114,71 @@ test('reply to non-focused grandchild status in a thread', async t => {
|
|||
.click(getNthComposeReplyButton(3))
|
||||
await verifyAriaSetSize(t, '4')
|
||||
})
|
||||
|
||||
async function replyToNthStatus (t, n, replyText, expectedN) {
|
||||
await t
|
||||
.click(getNthReplyButton(n))
|
||||
.typeText(getNthComposeReplyInput(n), replyText, { paste: true })
|
||||
.click(getNthComposeReplyButton(n))
|
||||
.expect(getNthStatusContent(expectedN).innerText).contains(replyText)
|
||||
}
|
||||
|
||||
test('no duplicates in threads', async t => {
|
||||
await loginAsFoobar(t)
|
||||
await t
|
||||
.hover(composeInput)
|
||||
.typeText(composeInput, 'this is my thread 1', { paste: true })
|
||||
.click(composeButton)
|
||||
.expect(getNthStatusContent(1).innerText).contains('this is my thread 1')
|
||||
.click(getNthStatus(1))
|
||||
.expect(getUrl()).contains('status')
|
||||
await replyToNthStatus(t, 1, 'this is my thread 2', 2)
|
||||
const [id1, id2] = await Promise.all([getNthStatusId(1)(), getNthStatusId(2)()])
|
||||
await t
|
||||
.click(getNthStatus(2))
|
||||
.expect(getUrl()).contains(id2)
|
||||
await replyToNthStatus(t, 2, 'this is my thread 3', 3)
|
||||
const id3 = await getNthStatusId(3)()
|
||||
await postReplyAs('quux', 'hey i am replying to 1', id1)
|
||||
await postReplyAs('admin', 'hey i am replying to 3', id3)
|
||||
await t
|
||||
.expect(getNthStatusContent(4).innerText).contains('hey i am replying to 3', { timeout: 20000 })
|
||||
const idReplyTo3 = await getNthStatusId(4)()
|
||||
await t
|
||||
.click(getNthStatus(4))
|
||||
.expect(getUrl()).contains(idReplyTo3)
|
||||
await postReplyAs('quux', 'hey check this reply', id1)
|
||||
await t
|
||||
.click(getNthStatus(2))
|
||||
.expect(getUrl()).contains(id2)
|
||||
.click(getNthStatus(3))
|
||||
.expect(getUrl()).contains(id3)
|
||||
await replyToNthStatus(t, 3, 'this is my thread 4', 5)
|
||||
await replyToNthStatus(t, 5, 'this is my thread 5', 6)
|
||||
const id5 = await getNthStatusId(6)()
|
||||
await postReplyAs('admin', 'hey i am replying to 1 again', id1)
|
||||
await t
|
||||
.click(getNthStatus(6))
|
||||
.expect(getUrl()).contains(id5)
|
||||
.click(getNthStatus(1))
|
||||
.expect(getUrl()).contains(id1)
|
||||
|
||||
await t
|
||||
.click(getNthStatus(6))
|
||||
.expect(getUrl()).contains(id5)
|
||||
await replyToNthStatus(t, 5, 'this is my thread 6', 6)
|
||||
await t
|
||||
.click(getNthStatus(1))
|
||||
.expect(getUrl()).contains(id1)
|
||||
|
||||
const contents = await getStatusContents()
|
||||
const contentsToCounts = new Map()
|
||||
for (const content of contents) {
|
||||
contentsToCounts.set(content, 1 + (contentsToCounts.get(content) || 0))
|
||||
}
|
||||
const duplicates = [...contentsToCounts.entries()].filter(arr => arr[1] > 1).map(arr => arr[0])
|
||||
|
||||
// there should be no duplicates
|
||||
await t
|
||||
.expect(duplicates).eql([])
|
||||
})
|
||||
|
|
|
@ -167,6 +167,27 @@ export const getActiveElementInsideNthStatus = exec(() => {
|
|||
return ''
|
||||
})
|
||||
|
||||
export const getNthStatusId = n => exec(() => {
|
||||
return document.querySelector(getNthStatusSelector(n))
|
||||
.getAttribute('id')
|
||||
.split('/')
|
||||
.slice(-1)[0]
|
||||
}, {
|
||||
dependencies: {
|
||||
getNthStatusSelector,
|
||||
n
|
||||
}
|
||||
})
|
||||
|
||||
export const getStatusContents = exec(() => {
|
||||
const res = []
|
||||
const elements = document.querySelectorAll('.list-item > article .status-content')
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
res.push(elements[i].innerText)
|
||||
}
|
||||
return res
|
||||
})
|
||||
|
||||
export const getTitleText = exec(() => document.head.querySelector('title') && document.head.querySelector('title').innerHTML)
|
||||
|
||||
export const goBack = exec(() => window.history.back())
|
||||
|
|
Loading…
Reference in a new issue