fix: fix aria-posinset should be 1-based (#1055)

* fix: fix aria-posinset should be 1-based

fixes #1053

* second attempt to fix tests

* try to fix test

*  fixup

* lint fix

* fix more tests

* simplify test math
This commit is contained in:
Nolan Lawson 2019-02-28 08:56:25 -08:00 committed by GitHub
parent b0aa86ef44
commit 63003c3763
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 580 additions and 579 deletions

View file

@ -6,7 +6,7 @@
<article id={elementId}
class={className}
tabindex="0"
aria-posinset={index}
aria-posinset={index + 1}
aria-setsize={length}
aria-label={ariaLabel}
on:applyFocusStylesToParent="noop()"

View file

@ -1,7 +1,7 @@
<article id={elementId}
class={className}
tabindex="0"
aria-posinset={index}
aria-posinset={index + 1}
aria-setsize={length}
aria-label={ariaLabel}
on:recalculateHeight

View file

@ -77,10 +77,12 @@ test('Logs in and logs out of localhost:3000', async t => {
test('Logs in, refreshes, then logs out', async t => {
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.expect(getNthStatus(1).exists).ok({ timeout: 30000 })
.hover(getNthStatus(1))
await reload()
await t
.hover(getNthStatus(0))
.expect(getNthStatus(1).exists).ok({ timeout: 30000 })
.hover(getNthStatus(1))
.click(settingsButton)
.click($('a').withText('Instances'))
.click($('a').withText('localhost:3000'))

View file

@ -14,11 +14,11 @@ test('Shows the home timeline', async t => {
await loginAsFoobar(t)
await t
.expect(getUrl()).eql('http://localhost:4002/')
.expect(getNthStatus(0).exists).ok({ timeout: 30000 })
.hover(getNthStatus(0))
.expect(getNthStatus(1).exists).ok({ timeout: 30000 })
.hover(getNthStatus(1))
.expect(getFirstVisibleStatus().exists).ok()
.expect(getFirstVisibleStatus().hasAttribute('aria-setsize')).ok()
.expect(getFirstVisibleStatus().getAttribute('aria-posinset')).eql('0')
.expect(getFirstVisibleStatus().getAttribute('aria-posinset')).eql('1')
await validateTimeline(t, homeTimeline)
@ -29,7 +29,7 @@ test('Shows notifications', async t => {
await loginAsFoobar(t)
await t
.expect(getUrl()).eql('http://localhost:4002/')
.expect(getNthStatus(0).exists).ok({ timeout: 30000 })
.expect(getNthStatus(1).exists).ok({ timeout: 30000 })
.click(notificationsNavButton)
.expect(getUrl()).contains('/notifications')
@ -40,7 +40,7 @@ test('Shows the local timeline', async t => {
await loginAsFoobar(t)
await t
.expect(getUrl()).eql('http://localhost:4002/')
.expect(getNthStatus(0).exists).ok({ timeout: 30000 })
.expect(getNthStatus(1).exists).ok({ timeout: 30000 })
.click(localTimelineNavButton)
.expect(getUrl()).contains('/local')
@ -51,7 +51,7 @@ test('Shows the federated timeline', async t => {
await loginAsFoobar(t)
await t
.expect(getUrl()).eql('http://localhost:4002/')
.expect(getNthStatus(0).exists).ok({ timeout: 30000 })
.expect(getNthStatus(1).exists).ok({ timeout: 30000 })
.click(communityNavButton)
.expect(getUrl()).contains('/community')
.click($('a').withText('Federated'))
@ -64,7 +64,7 @@ test('Shows favorites', async t => {
await loginAsFoobar(t)
await t
.expect(getUrl()).eql('http://localhost:4002/')
.expect(getNthStatus(0).exists).ok({ timeout: 30000 })
.expect(getNthStatus(1).exists).ok({ timeout: 30000 })
.click(communityNavButton)
.expect(getUrl()).contains('/community')
.click($('a').withText('Favorites'))

View file

@ -12,7 +12,7 @@ test("shows a user's pinned statuses", async t => {
.expect(getUrl()).contains('/community')
.click($('a[href="/pinned"]'))
.expect(getUrl()).contains('/pinned')
.expect($('.status-article').getAttribute('aria-posinset')).eql('0')
.expect($('.status-article').getAttribute('aria-posinset')).eql('1')
.expect($('.status-article').getAttribute('aria-setsize')).eql('1')
.expect($('.status-article .status-content').innerText).contains('this is unlisted')
})
@ -21,18 +21,18 @@ test("shows pinned statuses on a user's account page", async t => {
await loginAsFoobar(t)
await t
.navigateTo('/accounts/2')
.expect(getNthPinnedStatus(0).getAttribute('aria-posinset')).eql('0')
.expect(getNthPinnedStatus(0).getAttribute('aria-setsize')).eql('1')
.expect(getNthPinnedStatus(0).innerText).contains('this is unlisted')
.expect(getNthPinnedStatus(1).getAttribute('aria-posinset')).eql('1')
.expect(getNthPinnedStatus(1).getAttribute('aria-setsize')).eql('1')
.expect(getNthPinnedStatus(1).innerText).contains('this is unlisted')
})
test("shows pinned statuses on a user's account page 2", async t => {
await loginAsFoobar(t)
await t
.navigateTo('/accounts/3')
.expect(getNthPinnedStatus(0).getAttribute('aria-posinset')).eql('0')
.expect(getNthPinnedStatus(0).getAttribute('aria-setsize')).eql('2')
.expect(getNthPinnedStatus(0).innerText).contains('pinned toot 1')
.expect(getNthPinnedStatus(1).getAttribute('aria-posinset')).eql('1')
.expect(getNthPinnedStatus(1).getAttribute('aria-setsize')).eql('2')
.expect(getNthPinnedStatus(1).innerText).contains('pinned toot 2')
.expect(getNthPinnedStatus(1).innerText).contains('pinned toot 1')
.expect(getNthPinnedStatus(2).getAttribute('aria-setsize')).eql('2')
.expect(getNthPinnedStatus(2).innerText).contains('pinned toot 2')
})

View file

@ -8,20 +8,6 @@ fixture`005-status-types.js`
test('shows followers-only vs regular in home timeline', async t => {
await loginAsFoobar(t)
await t
.expect($(`${getNthStatusSelector(1)} .status-content`).innerText).contains('notification of unlisted message')
.expect($(`${getNthStatusSelector(1)} .status-toolbar button:nth-child(2)`).getAttribute('aria-label'))
.eql('Boost')
.expect($(`${getNthStatusSelector(1)} .status-toolbar button:nth-child(2)`).hasAttribute('disabled')).notOk()
.expect($(`${getNthStatusSelector(2)} .status-content`).innerText).contains('notification of followers-only message')
.expect($(`${getNthStatusSelector(2)} .status-toolbar button:nth-child(2)`).getAttribute('aria-label'))
.eql('Cannot be boosted because this is followers-only')
.expect($(`${getNthStatusSelector(2)} .status-toolbar button:nth-child(2)`).hasAttribute('disabled')).ok()
})
test('shows direct vs followers-only vs regular in notifications', async t => {
await loginAsFoobar(t)
await t
.navigateTo('/notifications')
.expect($(`${getNthStatusSelector(2)} .status-content`).innerText).contains('notification of unlisted message')
.expect($(`${getNthStatusSelector(2)} .status-toolbar button:nth-child(2)`).getAttribute('aria-label'))
.eql('Boost')
@ -30,8 +16,22 @@ test('shows direct vs followers-only vs regular in notifications', async t => {
.expect($(`${getNthStatusSelector(3)} .status-toolbar button:nth-child(2)`).getAttribute('aria-label'))
.eql('Cannot be boosted because this is followers-only')
.expect($(`${getNthStatusSelector(3)} .status-toolbar button:nth-child(2)`).hasAttribute('disabled')).ok()
.expect($(`${getNthStatusSelector(4)} .status-content`).innerText).contains('notification of direct message')
.expect($(`${getNthStatusSelector(4)} .status-toolbar button:nth-child(2)`).getAttribute('aria-label'))
.eql('Cannot be boosted because this is a direct message')
.expect($(`${getNthStatusSelector(4)} .status-toolbar button:nth-child(2)`).hasAttribute('disabled')).ok()
})
test('shows direct vs followers-only vs regular in notifications', async t => {
await loginAsFoobar(t)
await t
.navigateTo('/notifications')
.expect($(`${getNthStatusSelector(3)} .status-content`).innerText).contains('notification of unlisted message')
.expect($(`${getNthStatusSelector(3)} .status-toolbar button:nth-child(2)`).getAttribute('aria-label'))
.eql('Boost')
.expect($(`${getNthStatusSelector(3)} .status-toolbar button:nth-child(2)`).hasAttribute('disabled')).notOk()
.expect($(`${getNthStatusSelector(4)} .status-content`).innerText).contains('notification of followers-only message')
.expect($(`${getNthStatusSelector(4)} .status-toolbar button:nth-child(2)`).getAttribute('aria-label'))
.eql('Cannot be boosted because this is followers-only')
.expect($(`${getNthStatusSelector(4)} .status-toolbar button:nth-child(2)`).hasAttribute('disabled')).ok()
.expect($(`${getNthStatusSelector(5)} .status-content`).innerText).contains('notification of direct message')
.expect($(`${getNthStatusSelector(5)} .status-toolbar button:nth-child(2)`).getAttribute('aria-label'))
.eql('Cannot be boosted because this is a direct message')
.expect($(`${getNthStatusSelector(5)} .status-toolbar button:nth-child(2)`).hasAttribute('disabled')).ok()
})

View file

@ -8,28 +8,28 @@ fixture`006-tabindex.js`
test('shows correct tabindex in home timeline', async t => {
await loginAsFoobar(t)
await t
.expect(getNthStatus(0).getAttribute('tabindex')).eql('0')
.expect(getNthStatus(1).getAttribute('tabindex')).eql('0')
.expect(getNthStatus(2).getAttribute('tabindex')).eql('0')
.expect(getNthStatus(3).getAttribute('tabindex')).eql('0')
.expect(getNthStatus(4).getAttribute('tabindex')).eql('0')
})
test('shows correct tabindex in notifications', async t => {
await loginAsFoobar(t)
await t
.navigateTo('/notifications')
.expect(getNthStatus(0).getAttribute('tabindex')).eql('0')
.expect(getNthStatus(1).getAttribute('tabindex')).eql('0')
.expect(getNthStatus(2).getAttribute('tabindex')).eql('0')
.hover(getNthStatus(2))
.expect(getNthStatus(3).getAttribute('tabindex')).eql('0')
.hover(getNthStatus(3))
.expect(getNthStatus(4).getAttribute('tabindex')).eql('0')
.hover(getNthStatus(4))
.expect(getNthStatus(5).getAttribute('tabindex')).eql('0')
.hover(getNthStatus(5))
.expect(getNthStatus(6).getAttribute('tabindex')).eql('0')
.hover(getNthStatus(6))
.expect(getNthStatus(7).getAttribute('tabindex')).eql('0')
.expect(getNthStatus(7).getAttribute('aria-setsize')).eql('8')
.hover(getNthStatus(7))
.expect(getNthStatus(8).getAttribute('tabindex')).eql('0')
.expect(getNthStatus(8).getAttribute('aria-setsize')).eql('8')
})
test('shows correct tabindex in pinned statuses', async t => {
@ -37,6 +37,6 @@ test('shows correct tabindex in pinned statuses', async t => {
await t
.navigateTo('/pinned')
.expect($('.status-article').getAttribute('tabindex')).eql('0')
.expect($('.status-article').getAttribute('aria-posinset')).eql('0')
.expect($('.status-article').getAttribute('aria-posinset')).eql('1')
.expect($('.status-article').getAttribute('aria-setsize')).eql('1')
})

View file

@ -52,8 +52,8 @@ test('shows account profile statuses', async t => {
.click($('.status-author-name').withText(('quux')))
.expect(getUrl()).contains('/accounts/3')
.expect($('.pinned-statuses .status-article').getAttribute('aria-setsize')).eql('2')
.expect($('.pinned-statuses .status-article').getAttribute('aria-posinset')).eql('0')
.expect($('.timeline .status-article').getAttribute('aria-posinset')).eql('0')
.expect($('.pinned-statuses .status-article').getAttribute('aria-posinset')).eql('1')
.expect($('.timeline .status-article').getAttribute('aria-posinset')).eql('1')
await validateTimeline(t, quuxStatuses)
await t.expect($('.timeline .status-article').getAttribute('aria-setsize')).eql('27')
})

View file

@ -13,15 +13,15 @@ test('shows sensitive images and videos', async t => {
let kittenIdx = indexWhere(homeTimeline, _ => _.spoiler === 'kitten CW')
let videoIdx = indexWhere(homeTimeline, _ => _.content === 'secret video')
await scrollToStatus(t, kittenIdx)
await t.expect($(`${getNthStatusSelector(kittenIdx)} .status-media img`).exists).notOk()
.click($(`${getNthStatusSelector(kittenIdx)} .status-sensitive-media-button`))
.expect($(`${getNthStatusSelector(kittenIdx)} .status-media img`).getAttribute('alt')).eql('kitten')
.expect($(`${getNthStatusSelector(kittenIdx)} .status-media img`).hasAttribute('src')).ok()
.hover(getNthStatus(videoIdx))
.expect($(`${getNthStatusSelector(videoIdx)} .status-media .play-video-button`).exists).notOk()
.click($(`${getNthStatusSelector(videoIdx)} .status-sensitive-media-button`))
.expect($(`${getNthStatusSelector(videoIdx)} .status-media .play-video-button`).exists).ok()
await scrollToStatus(t, 1 + kittenIdx)
await t.expect($(`${getNthStatusSelector(1 + kittenIdx)} .status-media img`).exists).notOk()
.click($(`${getNthStatusSelector(1 + kittenIdx)} .status-sensitive-media-button`))
.expect($(`${getNthStatusSelector(1 + kittenIdx)} .status-media img`).getAttribute('alt')).eql('kitten')
.expect($(`${getNthStatusSelector(1 + kittenIdx)} .status-media img`).hasAttribute('src')).ok()
.hover(getNthStatus(1 + videoIdx))
.expect($(`${getNthStatusSelector(1 + videoIdx)} .status-media .play-video-button`).exists).notOk()
.click($(`${getNthStatusSelector(1 + videoIdx)} .status-sensitive-media-button`))
.expect($(`${getNthStatusSelector(1 + videoIdx)} .status-media .play-video-button`).exists).ok()
})
test('click and close image and video modals', async t => {
@ -30,17 +30,17 @@ test('click and close image and video modals', async t => {
let videoIdx = indexWhere(homeTimeline, _ => _.content === "here's a video")
let kittenIdx = indexWhere(homeTimeline, _ => _.content === "here's an animated kitten gif")
await scrollToStatus(t, videoIdx)
await scrollToStatus(t, 1 + videoIdx)
await t.expect(modalDialogContents.exists).notOk()
.click($(`${getNthStatusSelector(videoIdx)} .play-video-button`))
.click($(`${getNthStatusSelector(1 + videoIdx)} .play-video-button`))
.expect(modalDialogContents.exists).ok()
.expect($('.modal-dialog video').getAttribute('src')).contains('mp4')
.expect($('.modal-dialog video').getAttribute('poster')).contains('png')
.click(closeDialogButton)
.expect(modalDialogContents.exists).notOk()
.hover(getNthStatus(kittenIdx - 1))
.hover(getNthStatus(kittenIdx))
.click($(`${getNthStatusSelector(kittenIdx)} .show-image-button`))
.hover(getNthStatus(1 + kittenIdx - 1))
.hover(getNthStatus(1 + kittenIdx))
.click($(`${getNthStatusSelector(1 + kittenIdx)} .show-image-button`))
.expect(modalDialogContents.exists).ok()
.expect($('.modal-dialog video').getAttribute('src')).contains('mp4')
.expect($('.modal-dialog video').getAttribute('poster')).contains('png')

View file

@ -14,31 +14,31 @@ test('Shows a thread', async t => {
await t
.click($('a').withText('quux'))
await scrollToStatus(t, 26)
await scrollToStatus(t, 27)
await t
.hover(getNthStatus(26))
.click(getNthStatus(26))
.hover(getNthStatus(27))
.click(getNthStatus(27))
.expect(getUrl()).contains('/statuses/')
await validateTimeline(t, quuxThread)
await t.expect(getNthStatus(24).getAttribute('aria-setsize')).eql('25')
await t.expect(getNthStatus(25).getAttribute('aria-setsize')).eql('25')
})
test('Scrolls to proper point in thread', async t => {
await loginAsFoobar(t)
await t
.click($('a').withText('quux'))
.hover(getNthStatus(0))
.hover(getNthStatus(2))
.hover(getNthStatus(4))
.hover(getNthStatus(6))
.hover(getNthStatus(8))
.hover(getNthStatus(10))
.click(getNthStatus(10))
.hover(getNthStatus(1))
.hover(getNthStatus(3))
.hover(getNthStatus(5))
.hover(getNthStatus(7))
.hover(getNthStatus(9))
.hover(getNthStatus(11))
.click(getNthStatus(11))
.expect(getUrl()).contains('/statuses/')
.expect(getNthStatus(16).innerText).contains('unlisted thread 17')
.expect(Math.round(getNthStatus(16).boundingClientRect.top))
.expect(getNthStatus(17).innerText).contains('unlisted thread 17')
.expect(Math.round(getNthStatus(17).boundingClientRect.top))
.eql(Math.round($('.main-content').boundingClientRect.top))
})
@ -52,21 +52,21 @@ async function navigateToBazAccount (t) {
}
async function validateForkedThread (t) {
await t.hover(getNthStatus(1))
.click(getNthStatus(2))
await t.hover(getNthStatus(2))
.click(getNthStatus(3))
.expect(getUrl()).contains('/statuses')
await validateTimeline(t, bazThreadRelativeTo2B2)
await goBack()
await t.hover(getNthStatus(3))
.hover(getNthStatus(5))
.hover(getNthStatus(7))
.hover(getNthStatus(9))
.click(getNthStatus(9))
await t.hover(getNthStatus(4))
.hover(getNthStatus(6))
.hover(getNthStatus(8))
.hover(getNthStatus(10))
.click(getNthStatus(10))
.expect(getUrl()).contains('/statuses')
await validateTimeline(t, bazThreadRelativeTo2b)
await goBack()
await t.hover(getNthStatus(11))
.click(getNthStatus(11))
await t.hover(getNthStatus(12))
.click(getNthStatus(12))
.expect(getUrl()).contains('/statuses')
await validateTimeline(t, bazThreadRelativeTo2)
}

View file

@ -16,62 +16,62 @@ test('modal preserves focus', async t => {
let idx = indexWhere(homeTimeline, _ => _.content === "here's a video")
await scrollToStatus(t, idx)
await scrollToStatus(t, 1 + idx)
// explicitly hover-focus-click
await t.hover($(`${getNthStatusSelector(idx)} .play-video-button`))
await focus(`${getNthStatusSelector(idx)} .play-video-button`)()
await t.click($(`${getNthStatusSelector(idx)} .play-video-button`))
await t.hover($(`${getNthStatusSelector(1 + idx)} .play-video-button`))
await focus(`${getNthStatusSelector(1 + idx)} .play-video-button`)()
await t.click($(`${getNthStatusSelector(1 + idx)} .play-video-button`))
.click(closeDialogButton)
.expect(modalDialogContents.exists).notOk()
.expect(getActiveElementClassList()).contains('play-video-button')
.expect(getActiveElementInsideNthStatus()).eql(idx.toString())
.expect(getActiveElementInsideNthStatus()).eql((idx + 1).toString())
})
test('timeline preserves focus', async t => {
await loginAsFoobar(t)
// explicitly hover-focus-click
await t.hover(getNthStatus(0))
await focus(getNthStatusSelector(0))()
await t.click(getNthStatus(0))
await t.hover(getNthStatus(1))
await focus(getNthStatusSelector(1))()
await t.click(getNthStatus(1))
.expect(getUrl()).contains('/statuses/')
await goBack()
await t.expect(getUrl()).eql('http://localhost:4002/')
.expect(getActiveElementClassList()).contains('status-article')
.expect(getActiveElementClassList()).contains('status-in-timeline')
.expect(getActiveElementInsideNthStatus()).eql('0')
.expect(getActiveElementInsideNthStatus()).eql('1')
})
test('timeline link preserves focus', async t => {
await loginAsFoobar(t)
await t
.expect(getNthStatus(0).exists).ok({ timeout: 20000 })
.click($(`${getNthStatusSelector(0)} .status-header a`))
.expect(getNthStatus(1).exists).ok({ timeout: 20000 })
.click($(`${getNthStatusSelector(1)} .status-header a`))
.expect(getUrl()).contains('/accounts/')
.click(goBackButton)
.expect(getUrl()).eql('http://localhost:4002/')
.expect(getNthStatus(0).exists).ok()
.expect(getNthStatus(1).exists).ok()
.expect(getActiveElementInnerText()).eql('admin')
.click($(`${getNthStatusSelector(0)} .status-sidebar`))
.click($(`${getNthStatusSelector(1)} .status-sidebar`))
.expect(getUrl()).contains('/accounts/')
.click(goBackButton)
.expect(getUrl()).eql('http://localhost:4002/')
.expect(getActiveElementClassList()).contains('status-sidebar')
.expect(getActiveElementInsideNthStatus()).eql('0')
.expect(getActiveElementInsideNthStatus()).eql('1')
})
test('notification timeline preserves focus', async t => {
await loginAsFoobar(t)
await t
.navigateTo('/notifications')
await scrollToStatus(t, 5)
await t.click($(`${getNthStatusSelector(5)} .status-header a`))
await scrollToStatus(t, 6)
await t.click($(`${getNthStatusSelector(6)} .status-header a`))
.expect(getUrl()).contains('/accounts/')
.click(goBackButton)
.expect(getUrl()).contains('/notifications')
.expect(getNthStatus(0).exists).ok()
.expect(getNthStatus(1).exists).ok()
.expect(getActiveElementInnerText()).eql('quux')
.expect(getActiveElementInsideNthStatus()).eql('5')
.expect(getActiveElementInsideNthStatus()).eql('6')
})
test('thread preserves focus', async t => {
@ -80,33 +80,33 @@ test('thread preserves focus', async t => {
await loginAsFoobar(t)
await t
.navigateTo('/accounts/3')
.expect(getNthStatus(0).exists).ok({ timeout })
.hover(getNthStatus(0))
await scrollToStatus(t, 2)
await t.click(getNthStatus(2))
.expect(getNthStatus(1).exists).ok({ timeout })
.hover(getNthStatus(1))
await scrollToStatus(t, 3)
await t.click(getNthStatus(3))
.expect(getUrl()).contains('/statuses/')
.click($(`${getNthStatusSelector(24)} .status-sidebar`))
.click($(`${getNthStatusSelector(25)} .status-sidebar`))
.expect(getUrl()).contains('/accounts/')
.click(goBackButton)
.expect(getUrl()).contains('/statuses/')
.expect(getNthStatus(24).exists).ok()
.expect(getNthStatus(25).exists).ok()
.expect(getActiveElementClassList()).contains('status-sidebar')
.expect(getActiveElementInsideNthStatus()).eql('24')
.hover(getNthStatus(23))
.click(getNthStatus(23))
.expect($(`${getNthStatusSelector(23)} .status-absolute-date`).exists).ok({ timeout })
.expect(getActiveElementInsideNthStatus()).eql('25')
.hover(getNthStatus(24))
.click(getNthStatus(24))
.expect($(`${getNthStatusSelector(24)} .status-absolute-date`).exists).ok({ timeout })
await goBack()
await t.expect($(`${getNthStatusSelector(24)} .status-absolute-date`).exists).ok({ timeout })
await t.expect($(`${getNthStatusSelector(25)} .status-absolute-date`).exists).ok({ timeout })
.expect(getActiveElementClassList()).contains('status-article', { timeout })
.expect(getActiveElementClassList()).contains('status-in-timeline', { timeout })
.expect(getActiveElementInsideNthStatus()).eql('23', { timeout })
.expect(getActiveElementInsideNthStatus()).eql('24', { timeout })
})
test('reply preserves focus and moves focus to the text input', async t => {
await loginAsFoobar(t)
await t
.expect(getNthStatus(1).exists).ok({ timeout: 20000 })
.click(getNthReplyButton(1))
.expect(getNthStatus(2).exists).ok({ timeout: 20000 })
.click(getNthReplyButton(2))
.expect(getActiveElementClassList()).contains('compose-box-input')
})

View file

@ -11,7 +11,7 @@ fixture`011-reblog-favorites-count.js`
test('shows favorites', async t => {
await loginAsFoobar(t)
await t
.click(getNthStatus(0))
.click(getNthStatus(1))
.expect(getUrl()).contains('/statuses/')
.expect(getFavoritesCount()).eql(2)
.expect(favoritesCountElement.getAttribute('aria-label')).eql('Favorited 2 times')
@ -27,7 +27,7 @@ test('shows favorites', async t => {
test('shows boosts', async t => {
await loginAsFoobar(t)
await t
.click(getNthStatus(0))
.click(getNthStatus(1))
.expect(getUrl()).contains('/statuses/')
.expect(getReblogsCount()).eql(1)
.expect(reblogsCountElement.getAttribute('aria-label')).eql('Boosted 1 time')

View file

@ -120,9 +120,9 @@ test('inserts native emoji without typing anything', async t => {
test('cannot post an empty status', async t => {
await loginAsFoobar(t)
await t
.expect(getNthStatusContent(0).innerText).contains('pinned toot 1')
.expect(getNthStatusContent(1).innerText).contains('pinned toot 1')
.click(composeButton)
await sleep(2)
await t
.expect(getNthStatusContent(0).innerText).contains('pinned toot 1')
.expect(getNthStatusContent(1).innerText).contains('pinned toot 1')
})

View file

@ -6,7 +6,7 @@ fixture`016-external-links.js`
.page`http://localhost:4002`
function getAnchor (nthStatus, nthAnchor) {
return $(`${getNthStatusSelector(nthStatus)} .status-content a`).nth(nthAnchor)
return $(`${getNthStatusSelector(1 + nthStatus)} .status-content a`).nth(nthAnchor)
}
function getAnchorInProfile (n) {
@ -16,7 +16,7 @@ function getAnchorInProfile (n) {
test('converts external links in statuses', async t => {
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.hover(getNthStatus(1))
.navigateTo('/accounts/4')
.expect(getUrl()).contains('/accounts/4')
.expect(getAnchor(0, 0).getAttribute('href')).eql('/accounts/1')
@ -34,7 +34,7 @@ test('converts external links in statuses', async t => {
test('converts external links in profiles', async t => {
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.hover(getNthStatus(1))
.navigateTo('/accounts/4')
.expect(getUrl()).contains('/accounts/4')
.expect($('.account-profile-name').innerText).contains('External Lonk')

View file

@ -15,118 +15,118 @@ fixture`017-compose-reply.js`
test('account handle populated correctly for replies', async t => {
await loginAsFoobar(t)
await t
.click(getNthReplyButton(0))
.expect(getNthComposeReplyInput(0).value).eql('@quux ')
.typeText(getNthComposeReplyInput(0), 'hello quux', { paste: true })
.expect(getNthComposeReplyInput(0).value).eql('@quux hello quux')
.click(getNthReplyButton(1))
.expect(getNthComposeReplyInput(1).value).eql('@quux ')
.typeText(getNthComposeReplyInput(1), 'hello quux', { paste: true })
.expect(getNthComposeReplyInput(1).value).eql('@quux hello quux')
.click(notificationsNavButton)
.expect(getUrl()).contains('/notifications')
.click(homeNavButton)
.expect(getUrl()).notContains('/notifications')
.expect(getNthComposeReplyInput(0).value).eql('@quux hello quux')
.expect(getNthComposeReplyInput(1).value).eql('@quux hello quux')
.expect(composeInput.value).eql('')
.hover(getNthStatus(2))
.hover(getNthStatus(4))
.click(getNthReplyButton(4))
.expect(getNthComposeReplyInput(4).value).eql('')
.hover(getNthStatus(3))
.hover(getNthStatus(5))
.click(getNthReplyButton(5))
.expect(getNthComposeReplyInput(5).value).eql('')
})
test('replying to posts with mentions', async t => {
await loginAsFoobar(t)
await t
.click(getNthReplyButton(1))
.expect(getNthComposeReplyInput(1).value).eql('@admin ')
.click(getNthReplyButton(2))
.expect(getNthComposeReplyInput(2).value).eql('@admin ')
.navigateTo('/accounts/4')
.click(getNthReplyButton(0))
.expect(getNthComposeReplyInput(0).value).eql('@ExternalLinks @admin @quux ')
.click(getNthReplyButton(1))
.expect(getNthComposeReplyInput(1).value).eql('@ExternalLinks @admin @quux ')
})
test('replies have same privacy as replied-to status by default', async t => {
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.hover(getNthStatus(1))
.click(getNthReplyButton(1))
.expect(getNthPostPrivacyButton(1).getAttribute('aria-label')).eql('Adjust privacy (currently Unlisted)')
.click(getNthReplyButton(1))
.hover(getNthStatus(2))
.click(getNthReplyButton(2))
.expect(getNthPostPrivacyButton(2).getAttribute('aria-label')).eql('Adjust privacy (currently Followers-only)')
.expect(getNthPostPrivacyButton(2).getAttribute('aria-label')).eql('Adjust privacy (currently Unlisted)')
.click(getNthReplyButton(2))
.hover(getNthStatus(3))
.click(getNthReplyButton(3))
.expect(getNthPostPrivacyButton(3).getAttribute('aria-label')).eql('Adjust privacy (currently Followers-only)')
.click(getNthReplyButton(3))
.hover(getNthStatus(4))
.hover(getNthStatus(5))
.click(getNthReplyButton(5))
.expect(getNthPostPrivacyButton(5).getAttribute('aria-label')).eql('Adjust privacy (currently Public)')
.click(getNthReplyButton(5))
.hover(getNthStatus(6))
.click(getNthReplyButton(6))
.expect(getNthPostPrivacyButton(6).getAttribute('aria-label')).eql('Adjust privacy (currently Public)')
.click(getNthReplyButton(6))
})
test('replies have same CW as replied-to status', async t => {
await loginAsFoobar(t)
let kittenIdx = indexWhere(homeTimeline, _ => _.spoiler === 'kitten CW')
await scrollToStatus(t, kittenIdx)
await t.click(getNthReplyButton(kittenIdx))
.expect(getNthReplyContentWarningInput(kittenIdx).value).eql('kitten CW')
.click(getNthStatusRelativeDate(kittenIdx))
await scrollToStatus(t, 1 + kittenIdx)
await t.click(getNthReplyButton(1 + kittenIdx))
.expect(getNthReplyContentWarningInput(1 + kittenIdx).value).eql('kitten CW')
.click(getNthStatusRelativeDate(1 + kittenIdx))
.expect(getUrl()).contains('/statuses')
.click(getNthReplyButton(0))
.expect(getNthReplyContentWarningInput(0).value).eql('kitten CW')
.click(getNthReplyButton(1))
.expect(getNthReplyContentWarningInput(1).value).eql('kitten CW')
})
test('replies save deletions of CW', async t => {
await loginAsFoobar(t)
let kittenIdx = indexWhere(homeTimeline, _ => _.spoiler === 'kitten CW')
await scrollToStatus(t, kittenIdx)
await t.click(getNthReplyButton(kittenIdx))
.expect(getNthReplyContentWarningInput(kittenIdx).value).eql('kitten CW')
.click(getNthReplyContentWarningButton(kittenIdx))
.expect(getNthReplyContentWarningInput(kittenIdx).exists).notOk()
.click(getNthStatusRelativeDate(kittenIdx))
await scrollToStatus(t, 1 + kittenIdx)
await t.click(getNthReplyButton(1 + kittenIdx))
.expect(getNthReplyContentWarningInput(1 + kittenIdx).value).eql('kitten CW')
.click(getNthReplyContentWarningButton(1 + kittenIdx))
.expect(getNthReplyContentWarningInput(1 + kittenIdx).exists).notOk()
.click(getNthStatusRelativeDate(1 + kittenIdx))
.expect(getUrl()).contains('/statuses')
.click(getNthReplyButton(0))
.expect(getNthReplyContentWarningInput(0).exists).notOk()
.click(getNthReplyButton(1))
.expect(getNthReplyContentWarningInput(1).exists).notOk()
})
test('replies save changes to CW', async t => {
await loginAsFoobar(t)
let kittenIdx = indexWhere(homeTimeline, _ => _.spoiler === 'kitten CW')
await scrollToStatus(t, kittenIdx)
await t.click(getNthReplyButton(kittenIdx))
.expect(getNthReplyContentWarningInput(kittenIdx).value).eql('kitten CW')
.typeText(getNthReplyContentWarningInput(kittenIdx), ' yolo', { paste: true })
.expect(getNthReplyContentWarningInput(kittenIdx).value).eql('kitten CW yolo')
.click(getNthStatusRelativeDate(kittenIdx))
await scrollToStatus(t, 1 + kittenIdx)
await t.click(getNthReplyButton(1 + kittenIdx))
.expect(getNthReplyContentWarningInput(1 + kittenIdx).value).eql('kitten CW')
.typeText(getNthReplyContentWarningInput(1 + kittenIdx), ' yolo', { paste: true })
.expect(getNthReplyContentWarningInput(1 + kittenIdx).value).eql('kitten CW yolo')
.click(getNthStatusRelativeDate(1 + kittenIdx))
.expect(getUrl()).contains('/statuses')
.click(getNthReplyButton(0))
.expect(getNthReplyContentWarningInput(0).value).eql('kitten CW yolo')
.click(getNthReplyButton(1))
.expect(getNthReplyContentWarningInput(1).value).eql('kitten CW yolo')
})
test('replies save changes to post privacy', async t => {
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.hover(getNthStatus(1))
.click(getNthReplyButton(1))
.expect(getNthPostPrivacyButton(1).getAttribute('aria-label')).eql('Adjust privacy (currently Unlisted)')
.click(getNthReplyPostPrivacyButton(1))
.hover(getNthStatus(2))
.click(getNthReplyButton(2))
.expect(getNthPostPrivacyButton(2).getAttribute('aria-label')).eql('Adjust privacy (currently Unlisted)')
.click(getNthReplyPostPrivacyButton(2))
.click(getNthPostPrivacyOptionInDialog(1))
.expect(getNthPostPrivacyButton(1).getAttribute('aria-label')).eql('Adjust privacy (currently Public)')
.click(getNthStatusRelativeDate(1))
.expect(getNthPostPrivacyButton(2).getAttribute('aria-label')).eql('Adjust privacy (currently Public)')
.click(getNthStatusRelativeDate(2))
.expect(getUrl()).contains('/statuses')
.click(getNthReplyButton(0))
.expect(getNthPostPrivacyButton(0).getAttribute('aria-label')).eql('Adjust privacy (currently Public)')
.click(getNthReplyButton(1))
.expect(getNthPostPrivacyButton(1).getAttribute('aria-label')).eql('Adjust privacy (currently Public)')
})
test('replies are the same whatever thread they are in', async t => {
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.hover(getNthStatus(1))
.click(getNthReplyButton(1))
.typeText(getNthComposeReplyInput(1), 'this is a reply', { paste: true })
.expect(getNthComposeReplyInput(1).value).eql('@admin this is a reply')
.click(getNthStatusRelativeDate(1))
.hover(getNthStatus(2))
.click(getNthReplyButton(2))
.typeText(getNthComposeReplyInput(2), 'this is a reply', { paste: true })
.expect(getNthComposeReplyInput(2).value).eql('@admin this is a reply')
.click(getNthStatusRelativeDate(2))
.expect(getUrl()).contains('/statuses')
.click(getNthReplyButton(0))
.expect(getNthComposeReplyInput(0).value).eql('@admin this is a reply')
.click(getNthReplyButton(1))
.expect(getNthComposeReplyInput(1).value).eql('@admin this is a reply')
})

View file

@ -97,11 +97,11 @@ test('autosuggest only shows for one input', async t => {
await t
.hover(composeInput)
.typeText(composeInput, '@quu')
.hover(getNthStatus(0))
.click(getNthReplyButton(0))
.selectText(getNthComposeReplyInput(0))
.hover(getNthStatus(1))
.click(getNthReplyButton(1))
.selectText(getNthComposeReplyInput(1))
.pressKey('delete')
.typeText(getNthComposeReplyInput(0), 'uu')
.typeText(getNthComposeReplyInput(1), 'uu')
.expect($('.compose-autosuggest.shown').exists).notOk()
})
@ -112,11 +112,11 @@ test('autosuggest only shows for one input part 2', async t => {
.typeText(composeInput, '@adm')
.expect($('.compose-autosuggest.shown').exists).ok({ timeout })
.expect(getNthAutosuggestionResult(1).innerText).contains('@admin')
.hover(getNthStatus(0))
.click(getNthReplyButton(0))
.selectText(getNthComposeReplyInput(0))
.hover(getNthStatus(1))
.click(getNthReplyButton(1))
.selectText(getNthComposeReplyInput(1))
.pressKey('delete')
.typeText(getNthComposeReplyInput(0), '@dd')
.typeText(getNthComposeReplyInput(1), '@dd')
await sleep(1000)
await t.pressKey('backspace')
.expect($('.compose-autosuggest.shown').exists).notOk()

View file

@ -12,7 +12,7 @@ fixture`021-followers-follows.js`
test('shows followers and follows', async t => {
await loginAsFoobar(t)
await t
.click($(`${getNthStatusSelector(0)} .status-author-name`))
.click($(`${getNthStatusSelector(1)} .status-author-name`))
.expect(getUrl()).match(/\/accounts\/3$/)
.expect(followsButton.getAttribute('aria-label')).eql('Follows 2')
.click(followsButton)

View file

@ -17,12 +17,12 @@ fixture`022-status-aria-label.js`
test('basic aria-labels for statuses', async t => {
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.expect(getNthStatus(0).getAttribute('aria-label')).match(
.hover(getNthStatus(1))
.expect(getNthStatus(1).getAttribute('aria-label')).match(
/quux, pinned toot 1, .+ ago, @quux, Unlisted, Boosted by admin/i
)
.hover(getNthStatus(0))
.expect(getNthStatus(1).getAttribute('aria-label')).match(
.hover(getNthStatus(1))
.expect(getNthStatus(2).getAttribute('aria-label')).match(
/admin, @foobar notification of unlisted message, .* ago, @admin, Unlisted/i
)
})
@ -30,18 +30,18 @@ test('basic aria-labels for statuses', async t => {
test('aria-labels for CWed statuses', async t => {
await loginAsFoobar(t)
let kittenIdx = indexWhere(homeTimeline, _ => _.spoiler === 'kitten CW')
await scrollToStatus(t, kittenIdx)
await scrollToStatus(t, 1 + kittenIdx)
await t
.hover(getNthStatus(kittenIdx))
.expect(getNthStatus(kittenIdx).getAttribute('aria-label')).match(
.hover(getNthStatus(1 + kittenIdx))
.expect(getNthStatus(1 + kittenIdx).getAttribute('aria-label')).match(
/foobar, Content warning: kitten CW, .* ago, @foobar, Public/i
)
.click(getNthShowOrHideButton(kittenIdx))
.expect(getNthStatus(kittenIdx).getAttribute('aria-label')).match(
.click(getNthShowOrHideButton(1 + kittenIdx))
.expect(getNthStatus(1 + kittenIdx).getAttribute('aria-label')).match(
/foobar, here's a kitten with a CW, .* ago, @foobar, Public/i
)
.click(getNthShowOrHideButton(kittenIdx))
.expect(getNthStatus(kittenIdx).getAttribute('aria-label')).match(
.click(getNthShowOrHideButton(1 + kittenIdx))
.expect(getNthStatus(1 + kittenIdx).getAttribute('aria-label')).match(
/foobar, Content warning: kitten CW, .* ago, @foobar, Public/i
)
})
@ -50,28 +50,28 @@ test('aria-labels for notifications', async t => {
await loginAsFoobar(t)
await t
.click(notificationsNavButton)
.hover(getNthStatus(0))
.expect(getNthStatus(0).getAttribute('aria-label')).match(
/admin favorited your status, foobar, this is unlisted, .* ago, @foobar, Unlisted/i
)
.hover(getNthStatus(1))
.expect(getNthStatus(1).getAttribute('aria-label')).match(
/admin boosted your status, foobar, this is unlisted, .* ago, @foobar, Unlisted/i
/admin favorited your status, foobar, this is unlisted, .* ago, @foobar, Unlisted/i
)
.hover(getNthStatus(2))
.expect(getNthStatus(2).getAttribute('aria-label')).match(
/admin, @foobar notification of unlisted message, .* ago, @admin, Unlisted/i
/admin boosted your status, foobar, this is unlisted, .* ago, @foobar, Unlisted/i
)
await scrollToStatus(t, 4)
await t
.hover(getNthStatus(4))
.expect(getNthStatus(4).getAttribute('aria-label')).match(
/admin, @foobar notification of direct message, .* ago, @admin, Direct/i
.hover(getNthStatus(3))
.expect(getNthStatus(3).getAttribute('aria-label')).match(
/admin, @foobar notification of unlisted message, .* ago, @admin, Unlisted/i
)
await scrollToStatus(t, 5)
await t
.hover(getNthStatus(5))
.expect(getNthStatus(5).getAttribute('aria-label')).match(
/admin, @foobar notification of direct message, .* ago, @admin, Direct/i
)
await scrollToStatus(t, 6)
await t
.hover(getNthStatus(6))
.expect(getNthStatus(6).getAttribute('aria-label')).match(
/quux followed you, @quux/i
)
})
@ -83,16 +83,16 @@ test('can shorten aria-labels', async t => {
.click(generalSettingsButton)
.click($('#choice-disable-long-aria-labels'))
.click(homeNavButton)
.hover(getNthStatus(0))
.expect(getNthStatus(0).getAttribute('aria-label')).match(
.hover(getNthStatus(1))
.expect(getNthStatus(1).getAttribute('aria-label')).match(
/Unlisted status by quux/
)
.click(settingsNavButton)
.click(generalSettingsButton)
.click($('#choice-disable-long-aria-labels'))
.click(homeNavButton)
.hover(getNthStatus(0))
.expect(getNthStatus(0).getAttribute('aria-label')).match(
.hover(getNthStatus(1))
.expect(getNthStatus(1).getAttribute('aria-label')).match(
/quux, pinned toot 1, .+ ago, @quux, Unlisted, Boosted by admin/i
)
})

View file

@ -13,12 +13,12 @@ fixture`023-mark-media-as-sensitive.js`
async function checkSensitivityForStatus (t, idx, sensitive) {
if (sensitive) {
await t
.expect(getNthStatusSensitiveMediaButton(idx).exists).ok()
.expect(getNthStatusMedia(idx).exists).notOk()
.expect(getNthStatusSensitiveMediaButton(1 + idx).exists).ok()
.expect(getNthStatusMedia(1 + idx).exists).notOk()
} else {
await t
.expect(getNthStatusSensitiveMediaButton(idx).exists).notOk()
.expect(getNthStatusMedia(idx).exists).ok()
.expect(getNthStatusSensitiveMediaButton(1 + idx).exists).notOk()
.expect(getNthStatusMedia(1 + idx).exists).ok()
}
}
@ -29,7 +29,7 @@ async function checkSensitivity (t, shouldBeSensitive) {
let sensitiveAnimatedKittenIdx = indexWhere(homeTimeline, _ => _.content === "here's a secret animated kitten gif")
let animatedKittenIdx = indexWhere(homeTimeline, _ => _.content === "here's an animated kitten gif")
await t.hover(getNthStatus(0))
await t.hover(getNthStatus(1))
let expected = [
[ sensitiveKittenIdx, shouldBeSensitive(true) ],
@ -40,7 +40,7 @@ async function checkSensitivity (t, shouldBeSensitive) {
]
for (let [ idx, sensitive ] of expected) {
await scrollToStatus(t, sensitiveKittenIdx)
await scrollToStatus(t, 1 + sensitiveKittenIdx)
await checkSensitivityForStatus(t, idx, sensitive)
}
}

View file

@ -22,9 +22,9 @@ fixture`025-shortcuts-status.js`
async function activateStatus (t, idx) {
let timeout = 20000
for (let i = 0; i <= idx; i++) {
await t.expect(getNthStatus(i).exists).ok({ timeout })
await t.expect(getNthStatus(1 + i).exists).ok({ timeout })
.pressKey('j')
.expect(isNthStatusActive(i)()).ok()
.expect(isNthStatusActive(1 + i)()).ok()
}
}
@ -32,34 +32,34 @@ test('Shortcut j/k change the active status', async t => {
await loginAsFoobar(t)
await t
.expect(getUrl()).eql('http://localhost:4002/')
.expect(getNthStatus(0).exists).ok({ timeout: 30000 })
.expect(isNthStatusActive(0)()).notOk()
.pressKey('j')
.expect(isNthStatusActive(0)()).ok()
.expect(getNthStatus(1).exists).ok({ timeout: 30000 })
.expect(isNthStatusActive(1)()).notOk()
.pressKey('j')
.expect(isNthStatusActive(1)()).ok()
.pressKey('j')
.expect(isNthStatusActive(2)()).ok()
.pressKey('j')
.expect(isNthStatusActive(3)()).ok()
.pressKey('j')
.expect(isNthStatusActive(4)()).ok()
.pressKey('k')
.expect(isNthStatusActive(3)()).ok()
.pressKey('k')
.expect(isNthStatusActive(2)()).ok()
.pressKey('k')
.expect(isNthStatusActive(1)()).ok()
.pressKey('k')
.expect(isNthStatusActive(0)()).ok()
.expect(isNthStatusActive(1)()).notOk()
.expect(isNthStatusActive(2)()).notOk()
.expect(isNthStatusActive(3)()).notOk()
.expect(isNthStatusActive(4)()).notOk()
})
test('Shortcut j goes to the first visible status', async t => {
await loginAsFoobar(t)
await t
.expect(getUrl()).eql('http://localhost:4002/')
await scrollToStatus(t, 10)
await scrollToStatus(t, 11)
await t
.expect(getNthStatus(10).exists).ok({ timeout: 30000 })
.expect(getNthStatus(11).exists).ok({ timeout: 30000 })
.pressKey('j')
.expect(getActiveElementRectTop()).gte(0)
})
@ -68,15 +68,15 @@ test('Shortcut o opens active status, backspace goes back', async t => {
await loginAsFoobar(t)
await t
.expect(getUrl()).eql('http://localhost:4002/')
.expect(getNthStatus(2).exists).ok({ timeout: 30000 })
.expect(getNthStatus(3).exists).ok({ timeout: 30000 })
.pressKey('j') // activates status 0
.pressKey('j') // activates status 1
.pressKey('j') // activates status 2
.expect(isNthStatusActive(2)()).ok()
.expect(isNthStatusActive(3)()).ok()
.pressKey('o')
.expect(getUrl()).contains('/statuses/')
.pressKey('Backspace')
.expect(isNthStatusActive(2)()).ok()
.expect(isNthStatusActive(3)()).ok()
})
test('Shortcut x shows/hides spoilers', async t => {
@ -86,13 +86,13 @@ test('Shortcut x shows/hides spoilers', async t => {
.expect(getUrl()).eql('http://localhost:4002/')
await activateStatus(t, idx)
await t
.expect(isNthStatusActive(idx)()).ok()
.expect(getNthStatusSpoiler(idx).innerText).contains('kitten CW')
.expect(getNthStatusContent(idx).hasClass('shown')).notOk()
.expect(isNthStatusActive(1 + idx)()).ok()
.expect(getNthStatusSpoiler(1 + idx).innerText).contains('kitten CW')
.expect(getNthStatusContent(1 + idx).hasClass('shown')).notOk()
.pressKey('x')
.expect(getNthStatusContent(idx).hasClass('shown')).ok()
.expect(getNthStatusContent(1 + idx).hasClass('shown')).ok()
.pressKey('x')
.expect(getNthStatusContent(idx).hasClass('shown')).notOk()
.expect(getNthStatusContent(1 + idx).hasClass('shown')).notOk()
})
test('Shortcut y shows/hides sensitive image', async t => {
@ -102,13 +102,13 @@ test('Shortcut y shows/hides sensitive image', async t => {
.expect(getUrl()).eql('http://localhost:4002/')
await activateStatus(t, idx)
await t
.expect(isNthStatusActive(idx)()).ok()
.expect(getNthStatusSensitiveMediaButton(idx).exists).ok()
.expect(getNthStatusMedia(idx).exists).notOk()
.expect(isNthStatusActive(1 + idx)()).ok()
.expect(getNthStatusSensitiveMediaButton(1 + idx).exists).ok()
.expect(getNthStatusMedia(1 + idx).exists).notOk()
.pressKey('y')
.expect(getNthStatusMedia(idx).exists).ok()
.expect(getNthStatusMedia(1 + idx).exists).ok()
.pressKey('y')
.expect(getNthStatusMedia(idx).exists).notOk()
.expect(getNthStatusMedia(1 + idx).exists).notOk()
})
test('Shortcut f toggles favorite status', async t => {
@ -116,14 +116,14 @@ test('Shortcut f toggles favorite status', async t => {
await loginAsFoobar(t)
await t
.expect(getUrl()).eql('http://localhost:4002/')
.expect(getNthStatus(idx).exists).ok({ timeout: 30000 })
.expect(getNthFavorited(idx)).eql('false')
.expect(getNthStatus(1 + idx).exists).ok({ timeout: 30000 })
.expect(getNthFavorited(1 + idx)).eql('false')
.pressKey('j '.repeat(idx + 1))
.expect(isNthStatusActive(idx)()).ok()
.expect(isNthStatusActive(1 + idx)()).ok()
.pressKey('f')
.expect(getNthFavorited(idx)).eql('true')
.expect(getNthFavorited(1 + idx)).eql('true')
.pressKey('f')
.expect(getNthFavorited(idx)).eql('false')
.expect(getNthFavorited(1 + idx)).eql('false')
})
test('Shortcut p toggles profile', async t => {
@ -131,9 +131,9 @@ test('Shortcut p toggles profile', async t => {
await loginAsFoobar(t)
await t
.expect(getUrl()).eql('http://localhost:4002/')
.expect(getNthStatus(idx).exists).ok({ timeout: 30000 })
.expect(getNthStatus(1 + idx).exists).ok({ timeout: 30000 })
.pressKey('j '.repeat(idx + 1))
.expect(isNthStatusActive(idx)()).ok()
.expect(isNthStatusActive(1 + idx)()).ok()
.pressKey('p')
.expect(getUrl()).contains('/accounts/3')
})
@ -143,9 +143,9 @@ test('Shortcut m toggles mention', async t => {
await loginAsFoobar(t)
await t
.expect(getUrl()).eql('http://localhost:4002/')
.expect(getNthStatus(idx).exists).ok({ timeout: 30000 })
.expect(getNthStatus(1 + idx).exists).ok({ timeout: 30000 })
.pressKey('j '.repeat(idx + 1))
.expect(isNthStatusActive(idx)()).ok()
.expect(isNthStatusActive(1 + idx)()).ok()
.pressKey('m')
.expect(composeModalInput.value).eql('@quux ')
.click(closeDialogButton)
@ -156,32 +156,32 @@ test('Shortcut j/k change the active status on a thread', async t => {
await loginAsFoobar(t)
await t
.click($('a').withText('quux'))
await scrollToStatus(t, 2)
await scrollToStatus(t, 3)
await t
.click(getNthStatus(2))
.click(getNthStatus(3))
.expect(getUrl()).contains('/statuses')
await scrollToStatus(t, 0)
await scrollToStatus(t, 1)
await scrollToTop()
await t
.expect(getNthStatus(0).exists).ok({ timeout: 30000 })
.expect(isNthStatusActive(0)()).notOk()
.pressKey('j')
.expect(isNthStatusActive(0)()).ok()
.expect(getNthStatus(1).exists).ok({ timeout: 30000 })
.expect(isNthStatusActive(1)()).notOk()
.pressKey('j')
.expect(isNthStatusActive(1)()).ok()
.pressKey('j')
.expect(isNthStatusActive(2)()).ok()
.pressKey('j')
.expect(isNthStatusActive(3)()).ok()
.pressKey('j')
.expect(isNthStatusActive(4)()).ok()
.pressKey('k')
.expect(isNthStatusActive(3)()).ok()
.pressKey('k')
.expect(isNthStatusActive(2)()).ok()
.pressKey('k')
.expect(isNthStatusActive(1)()).ok()
.pressKey('k')
.expect(isNthStatusActive(0)()).ok()
.expect(isNthStatusActive(1)()).notOk()
.expect(isNthStatusActive(2)()).notOk()
.expect(isNthStatusActive(3)()).notOk()
.expect(isNthStatusActive(4)()).notOk()
})
test('Shortcut j/k change the active status on pinned statuses', async t => {
@ -190,27 +190,27 @@ test('Shortcut j/k change the active status on pinned statuses', async t => {
.click($('a').withText('quux'))
.expect(getUrl()).contains('/accounts')
await t
.expect(getNthStatus(0).exists).ok({ timeout: 30000 })
.expect(isNthStatusActive(0)()).notOk()
.pressKey('j')
.expect(isNthStatusActive(0)()).ok()
.expect(isActiveStatusPinned()).eql(true)
.expect(getNthStatus(1).exists).ok({ timeout: 30000 })
.expect(isNthStatusActive(1)()).notOk()
.pressKey('j')
.expect(isNthStatusActive(1)()).ok()
.expect(isActiveStatusPinned()).eql(true)
.pressKey('j')
.expect(isNthStatusActive(0)()).ok()
.expect(isActiveStatusPinned()).eql(false)
.expect(isNthStatusActive(2)()).ok()
.expect(isActiveStatusPinned()).eql(true)
.pressKey('j')
.expect(isNthStatusActive(1)()).ok()
.expect(isActiveStatusPinned()).eql(false)
.pressKey('k')
.expect(isNthStatusActive(0)()).ok()
.pressKey('j')
.expect(isNthStatusActive(2)()).ok()
.expect(isActiveStatusPinned()).eql(false)
.pressKey('k')
.expect(isNthStatusActive(1)()).ok()
.expect(isActiveStatusPinned()).eql(false)
.pressKey('k')
.expect(isNthStatusActive(2)()).ok()
.expect(isActiveStatusPinned()).eql(true)
.pressKey('k')
.expect(isNthStatusActive(0)()).ok()
.expect(isNthStatusActive(1)()).ok()
.expect(isActiveStatusPinned()).eql(true)
})

View file

@ -18,14 +18,14 @@ test('Shortcut f toggles favorite status in notification', async t => {
.expect(getUrl()).eql('http://localhost:4002/')
.click(notificationsNavButton)
.expect(getUrl()).contains('/notifications')
.expect(getNthStatus(idx).exists).ok({ timeout: 30000 })
.expect(getNthFavorited(idx)).eql('false')
.expect(getNthStatus(1 + idx).exists).ok({ timeout: 30000 })
.expect(getNthFavorited(1 + idx)).eql('false')
.pressKey('j '.repeat(idx + 1))
.expect(isNthStatusActive(idx)()).ok()
.expect(isNthStatusActive(1 + idx)()).ok()
.pressKey('f')
.expect(getNthFavorited(idx)).eql('true')
.expect(getNthFavorited(1 + idx)).eql('true')
.pressKey('f')
.expect(getNthFavorited(idx)).eql('false')
.expect(getNthFavorited(1 + idx)).eql('false')
})
test('Shortcut p toggles profile in a follow notification', async t => {
@ -35,14 +35,14 @@ test('Shortcut p toggles profile in a follow notification', async t => {
.expect(getUrl()).eql('http://localhost:4002/')
.click(notificationsNavButton)
.expect(getUrl()).contains('/notifications')
.expect(getNthStatus(0).exists).ok({ timeout: 30000 })
.expect(getNthStatus(1).exists).ok({ timeout: 30000 })
.pressKey('j '.repeat(idx + 1))
.expect(isNthStatusActive(idx)()).ok()
.expect(isNthStatusActive(1 + idx)()).ok()
.pressKey('p')
.expect(getUrl()).contains('/accounts/3')
await goBack()
await t
.expect(isNthStatusActive(idx)()).ok() // focus preserved
.expect(isNthStatusActive(1 + idx)()).ok() // focus preserved
})
test('Shortcut m toggles mention in a follow notification', async t => {
@ -52,9 +52,9 @@ test('Shortcut m toggles mention in a follow notification', async t => {
.expect(getUrl()).eql('http://localhost:4002/')
.click(notificationsNavButton)
.expect(getUrl()).contains('/notifications')
.expect(getNthStatus(0).exists).ok({ timeout: 30000 })
.expect(getNthStatus(1).exists).ok({ timeout: 30000 })
.pressKey('j '.repeat(idx + 1))
.expect(isNthStatusActive(idx)()).ok()
.expect(isNthStatusActive(1 + idx)()).ok()
.pressKey('m')
.expect(composeModalInput.value).eql('@quux ')
.click(closeDialogButton)
@ -68,9 +68,9 @@ test('Shortcut p refers to booster in a boost notification', async t => {
.expect(getUrl()).eql('http://localhost:4002/')
.click(notificationsNavButton)
.expect(getUrl()).contains('/notifications')
.expect(getNthStatus(0).exists).ok({ timeout: 30000 })
.expect(getNthStatus(1).exists).ok({ timeout: 30000 })
.pressKey('j '.repeat(idx + 1))
.expect(isNthStatusActive(idx)()).ok()
.expect(isNthStatusActive(1 + idx)()).ok()
.pressKey('p')
.expect(getUrl()).contains('/accounts/1')
})
@ -82,9 +82,9 @@ test('Shortcut m refers to favoriter in a favorite notification', async t => {
.expect(getUrl()).eql('http://localhost:4002/')
.click(notificationsNavButton)
.expect(getUrl()).contains('/notifications')
.expect(getNthStatus(0).exists).ok({ timeout: 30000 })
.expect(getNthStatus(1).exists).ok({ timeout: 30000 })
.pressKey('j '.repeat(idx + 1))
.expect(isNthStatusActive(idx)()).ok()
.expect(isNthStatusActive(1 + idx)()).ok()
.pressKey('m')
.expect(composeModalInput.value).eql('@admin ')
.click(closeDialogButton)

View file

@ -13,7 +13,7 @@ fixture`028-report-ui.js`
test('Can open a report UI from a status', async t => {
await loginAsFoobar(t)
await t
.click(getNthStatusOptionsButton(0))
.click(getNthStatusOptionsButton(1))
.click($('.modal-dialog button').withText('Report'))
.expect(modalDialog.innerText).contains('You are reporting @quux')
.expect(modalDialog.find('.recent-statuses').innerText).contains('pinned toot 2')

View file

@ -13,72 +13,72 @@ fixture`100-favorite-unfavorite.js`
test('favorites a status', async t => {
await loginAsFoobar(t)
await t
.hover(getNthStatus(4))
.expect(getNthFavorited(4)).eql('false')
.click(getNthFavoriteButton(4))
.expect(getNthFavorited(4)).eql('true')
.hover(getNthStatus(5))
.expect(getNthFavorited(5)).eql('false')
.click(getNthFavoriteButton(5))
.expect(getNthFavorited(5)).eql('true')
// scroll down and back up to force an unrender
await scrollToBottom()
await sleep(1)
await scrollToTop()
await t
.hover(getNthStatus(4))
.expect(getNthFavorited(4)).eql('true')
.hover(getNthStatus(5))
.expect(getNthFavorited(5)).eql('true')
.click(notificationsNavButton)
.click(homeNavButton)
.expect(getNthFavorited(4)).eql('true')
.expect(getNthFavorited(5)).eql('true')
.click(notificationsNavButton)
.expect(getUrl()).contains('/notifications')
.click(homeNavButton)
.expect(getUrl()).eql('http://localhost:4002/')
.hover(getNthStatus(4))
.expect(getNthFavorited(4)).eql('true')
.click(getNthFavoriteButton(4))
.expect(getNthFavorited(4)).eql('false')
.hover(getNthStatus(5))
.expect(getNthFavorited(5)).eql('true')
.click(getNthFavoriteButton(5))
.expect(getNthFavorited(5)).eql('false')
})
test('unfavorites a status', async t => {
await loginAsFoobar(t)
await t
.expect(getNthFavorited(1)).eql('true')
.click(getNthFavoriteButton(1))
.expect(getNthFavorited(1)).eql('false')
.expect(getNthFavorited(2)).eql('true')
.click(getNthFavoriteButton(2))
.expect(getNthFavorited(2)).eql('false')
// scroll down and back up to force an unrender
await scrollToBottom()
await sleep(1)
await scrollToTop()
await t
.expect(getNthFavorited(1)).eql('false')
.expect(getNthFavorited(2)).eql('false')
.click(notificationsNavButton)
.click(homeNavButton)
.expect(getNthFavorited(1)).eql('false')
.expect(getNthFavorited(2)).eql('false')
.click(notificationsNavButton)
.navigateTo('/')
.expect(getNthFavorited(1)).eql('false')
.click(getNthFavoriteButton(1))
.expect(getNthFavorited(1)).eql('true')
.expect(getNthFavorited(2)).eql('false')
.click(getNthFavoriteButton(2))
.expect(getNthFavorited(2)).eql('true')
})
test('Keeps the correct favorites count', async t => {
await loginAsFoobar(t)
let idx = indexWhere(homeTimeline, _ => _.content === 'this is unlisted')
await t
.hover(getNthStatus(idx))
.click(getNthFavoriteButton(idx))
.expect(getNthFavorited(idx)).eql('true')
.click(getNthStatus(idx))
.hover(getNthStatus(1 + idx))
.click(getNthFavoriteButton(1 + idx))
.expect(getNthFavorited(1 + idx)).eql('true')
.click(getNthStatus(1 + idx))
.expect(getUrl()).contains('/status')
.expect(getNthFavorited(0)).eql('true')
.expect(getNthFavorited(1)).eql('true')
.expect(getFavoritesCount()).eql(2)
.click(homeNavButton)
.expect(getUrl()).eql('http://localhost:4002/')
.hover(getNthStatus(idx))
.click(getNthFavoriteButton(idx))
.expect(getNthFavorited(idx)).eql('false')
.click(getNthStatus(idx))
.hover(getNthStatus(1 + idx))
.click(getNthFavoriteButton(1 + idx))
.expect(getNthFavorited(1 + idx)).eql('false')
.click(getNthStatus(1 + idx))
.expect(getUrl()).contains('/status')
.expect(getNthFavorited(0)).eql('false')
.expect(getNthFavorited(1)).eql('false')
.expect(getFavoritesCount()).eql(1)
})

View file

@ -12,58 +12,58 @@ test('reblogs a status', async t => {
await postAs('foobar', 'hello this should be reblogged')
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.expect(getNthStatusContent(0).innerText).contains('should be reblogged')
.expect(getNthReblogged(0)).eql('false')
.click(getNthReblogButton(0))
.expect(getNthReblogged(0)).eql('true')
.hover(getNthStatus(1))
.expect(getNthStatusContent(1).innerText).contains('should be reblogged')
.expect(getNthReblogged(1)).eql('false')
.click(getNthReblogButton(1))
.expect(getNthReblogged(1)).eql('true')
// scroll down and back up to force an unrender
await scrollToBottom()
await sleep(1)
await scrollToTop()
await t
.hover(getNthStatus(0))
.expect(getNthReblogged(0)).eql('true')
.hover(getNthStatus(1))
.expect(getNthReblogged(1)).eql('true')
.click(notificationsNavButton)
.click(homeNavButton)
.expect(getNthReblogged(0)).eql('true')
.expect(getNthReblogged(1)).eql('true')
.click(notificationsNavButton)
.expect(getUrl()).contains('/notifications')
.click(homeNavButton)
.expect(getUrl()).eql('http://localhost:4002/')
.expect(getNthReblogged(0)).eql('true')
.click(getNthReblogButton(0))
.expect(getNthReblogged(0)).eql('false')
.expect(getNthReblogged(1)).eql('true')
.click(getNthReblogButton(1))
.expect(getNthReblogged(1)).eql('false')
})
test('unreblogs a status', async t => {
await postAs('foobar', 'woot i wanna reblog this')
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.expect(getNthStatusContent(0).innerText).contains('woot i wanna')
.expect(getNthReblogged(0)).eql('false')
.click(getNthReblogButton(0))
.expect(getNthReblogged(0)).eql('true')
.click(getNthReblogButton(0))
.expect(getNthReblogged(0)).eql('false')
.hover(getNthStatus(1))
.expect(getNthStatusContent(1).innerText).contains('woot i wanna')
.expect(getNthReblogged(1)).eql('false')
.click(getNthReblogButton(1))
.expect(getNthReblogged(1)).eql('true')
.click(getNthReblogButton(1))
.expect(getNthReblogged(1)).eql('false')
// scroll down and back up to force an unrender
await scrollToBottom()
await sleep(1)
await scrollToTop()
await t
.hover(getNthStatus(0))
.expect(getNthReblogged(0)).eql('false')
.hover(getNthStatus(1))
.expect(getNthReblogged(1)).eql('false')
.click(notificationsNavButton)
.click(homeNavButton)
.expect(getNthReblogged(0)).eql('false')
.expect(getNthReblogged(1)).eql('false')
.click(notificationsNavButton)
.navigateTo('/')
.expect(getNthReblogged(0)).eql('false')
.click(getNthReblogButton(0))
.expect(getNthReblogged(0)).eql('true')
.expect(getNthReblogged(1)).eql('false')
.click(getNthReblogButton(1))
.expect(getNthReblogged(1)).eql('true')
})
test('Keeps the correct reblogs count', async t => {
@ -72,20 +72,20 @@ test('Keeps the correct reblogs count', async t => {
await reblogStatusAs('admin', id)
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.expect(getNthStatusContent(0).innerText).contains('this will be reblogged')
.expect(getNthReblogged(0)).eql('true')
.click(getNthStatus(0))
.hover(getNthStatus(1))
.expect(getNthStatusContent(1).innerText).contains('this will be reblogged')
.expect(getNthReblogged(1)).eql('true')
.click(getNthStatus(1))
.expect(getUrl()).contains('/status')
.expect(getNthReblogged(0)).eql('true')
.expect(getNthReblogged(1)).eql('true')
.expect(getReblogsCount()).eql(2)
.click(homeNavButton)
.expect(getUrl()).eql('http://localhost:4002/')
.hover(getNthStatus(0))
.click(getNthReblogButton(0))
.expect(getNthReblogged(0)).eql('false')
.click(getNthStatus(0))
.hover(getNthStatus(1))
.click(getNthReblogButton(1))
.expect(getNthReblogged(1)).eql('false')
.click(getNthStatus(1))
.expect(getUrl()).contains('/status')
.expect(getNthReblogged(0)).eql('false')
.expect(getNthReblogged(1)).eql('false')
.expect(getReblogsCount()).eql(1)
})

View file

@ -13,7 +13,7 @@ test('shows unread notification', async t => {
await t
.expect(notificationsNavButton.getAttribute('aria-label')).eql('Notifications')
.expect(getTitleText()).eql('localhost:3000 · Home')
.expect(getNthStatusContent(0).innerText).contains('somebody please favorite this to validate me', {
.expect(getNthStatusContent(1).innerText).contains('somebody please favorite this to validate me', {
timeout: 20000
})
await favoriteStatusAs('admin', id)
@ -26,8 +26,8 @@ test('shows unread notification', async t => {
.expect(getUrl()).contains('/notifications')
.expect(notificationsNavButton.getAttribute('aria-label')).eql('Notifications (current page)')
.expect(getTitleText()).eql('localhost:3000 · Notifications')
.expect(getNthStatus(0).innerText).contains('somebody please favorite this to validate me')
.expect(getNthStatus(0).innerText).match(/admin\s+favorited your status/)
.expect(getNthStatus(1).innerText).contains('somebody please favorite this to validate me')
.expect(getNthStatus(1).innerText).match(/admin\s+favorited your status/)
await t
.click(homeNavButton)
.expect(notificationsNavButton.getAttribute('aria-label')).eql('Notifications')
@ -40,7 +40,7 @@ test('shows unread notifications, more than one', async t => {
await t
.expect(notificationsNavButton.getAttribute('aria-label')).eql('Notifications')
.expect(getTitleText()).eql('localhost:3000 · Home')
.expect(getNthStatusContent(0).innerText).contains('I need lots of favorites on this one', {
.expect(getNthStatusContent(1).innerText).contains('I need lots of favorites on this one', {
timeout: 20000
})
await favoriteStatusAs('admin', id)
@ -54,7 +54,7 @@ test('shows unread notifications, more than one', async t => {
.expect(getUrl()).contains('/notifications')
.expect(notificationsNavButton.getAttribute('aria-label')).eql('Notifications (current page)')
.expect(getTitleText()).eql('localhost:3000 · Notifications')
.expect(getNthStatus(0).innerText).contains('I need lots of favorites on this one')
.expect(getNthStatus(1).innerText).contains('I need lots of favorites on this one')
await t
.click(homeNavButton)
.expect(notificationsNavButton.getAttribute('aria-label')).eql('Notifications')

View file

@ -13,28 +13,28 @@ test('statuses show up in home timeline', async t => {
await t
.typeText(composeInput, 'hello world', { paste: true })
.click(postStatusButton)
.expect(getNthStatus(0).innerText).contains('hello world')
.expect(getNthStatus(1).innerText).contains('hello world')
.click(notificationsNavButton)
.expect(getUrl()).contains('/notifications')
.click(homeNavButton)
.expect(getUrl()).eql('http://localhost:4002/')
.expect(getNthStatus(0).innerText).contains('hello world')
.expect(getNthStatus(1).innerText).contains('hello world')
.navigateTo('/')
.expect(getNthStatus(0).innerText).contains('hello world')
.expect(getNthStatus(1).innerText).contains('hello world')
})
test('statuses in threads show up in right order', async t => {
await loginAsFoobar(t)
await t
.navigateTo('/accounts/5')
.click(getNthStatus(2))
.click(getNthStatus(3))
.expect(getUrl()).contains('/statuses')
.click(getNthReplyButton(3))
.typeText(getNthComposeReplyInput(3), 'my reply!', { paste: true })
.click(getNthComposeReplyButton(3))
.expect(getNthComposeReplyInput(3).exists).notOk()
.expect(getNthStatus(5).innerText).contains('@baz my reply!')
.click(getNthReplyButton(4))
.typeText(getNthComposeReplyInput(4), 'my reply!', { paste: true })
.click(getNthComposeReplyButton(4))
.expect(getNthComposeReplyInput(4).exists).notOk()
.expect(getNthStatus(6).innerText).contains('@baz my reply!')
.navigateTo('/accounts/5')
.click(getNthStatus(2))
.expect(getNthStatus(5).innerText).contains('@baz my reply!')
.click(getNthStatus(3))
.expect(getNthStatus(6).innerText).contains('@baz my reply!')
})

View file

@ -10,23 +10,23 @@ fixture`104-streaming.js`
test('new incoming statuses show up immediately', async t => {
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.hover(getNthStatus(1))
await postAs('admin', 'hello my baby hello my honey')
await t.expect(getNthStatus(0).innerText).contains('hello my baby hello my honey')
await t.expect(getNthStatus(1).innerText).contains('hello my baby hello my honey')
})
test('new incoming toots show a button if scrolled down', async t => {
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.hover(getNthStatus(2))
.hover(getNthStatus(4))
.hover(getNthStatus(1))
.hover(getNthStatus(3))
.hover(getNthStatus(5))
await sleep(1000)
await postAs('admin', 'hello my ragtime gal')
await postAs('admin', 'send me a kiss by wire')
await sleep(4000)
await t.hover(getNthStatus(2))
.hover(getNthStatus(0))
await t.hover(getNthStatus(3))
.hover(getNthStatus(1))
await scrollToTop()
await sleep(1000)
await t
@ -36,11 +36,11 @@ test('new incoming toots show a button if scrolled down', async t => {
await t.expect(showMoreButton.innerText).contains('Show 3 more')
.click(showMoreButton)
await t
.expect(getNthStatus(0).innerText).contains("baby my heart's on fire")
.expect(getNthStatus(1).innerText).contains('send me a kiss by wire')
.expect(getNthStatus(2).innerText).contains('hello my ragtime gal')
.expect(getNthStatus(1).innerText).contains("baby my heart's on fire")
.expect(getNthStatus(2).innerText).contains('send me a kiss by wire')
.expect(getNthStatus(3).innerText).contains('hello my ragtime gal')
.navigateTo('/')
.expect(getNthStatus(0).innerText).contains("baby my heart's on fire")
.expect(getNthStatus(1).innerText).contains('send me a kiss by wire')
.expect(getNthStatus(2).innerText).contains('hello my ragtime gal')
.expect(getNthStatus(1).innerText).contains("baby my heart's on fire")
.expect(getNthStatus(2).innerText).contains('send me a kiss by wire')
.expect(getNthStatus(3).innerText).contains('hello my ragtime gal')
})

View file

@ -12,45 +12,45 @@ test('deleted statuses are removed from the timeline', async t => {
let timeout = 20000
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.hover(getNthStatus(1))
let status = await postAs('admin', "I'm gonna delete this")
await t.expect(getNthStatus(0).innerText).contains("I'm gonna delete this", { timeout })
await t.expect(getNthStatus(1).innerText).contains("I'm gonna delete this", { timeout })
await deleteAs('admin', status.id)
await t.expect(getNthStatus(0).innerText).notContains("I'm gonna delete this", { timeout })
await t.expect(getNthStatus(1).innerText).notContains("I'm gonna delete this", { timeout })
await clickToNotificationsAndBackHome(t)
await t.expect(getNthStatus(0).innerText).notContains("I'm gonna delete this", { timeout })
await t.expect(getNthStatus(1).innerText).notContains("I'm gonna delete this", { timeout })
await t.navigateTo('/notifications')
await forceOffline()
await t.click(homeNavButton)
await t.expect(getNthStatus(0).innerText).notContains("I'm gonna delete this", { timeout })
await t.expect(getNthStatus(1).innerText).notContains("I'm gonna delete this", { timeout })
await forceOnline()
await t
.navigateTo('/')
.expect(getNthStatus(0).innerText).notContains("I'm gonna delete this", { timeout })
.expect(getNthStatus(1).innerText).notContains("I'm gonna delete this", { timeout })
})
test('deleted statuses are removed from threads', async t => {
let timeout = 20000
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.hover(getNthStatus(1))
let status = await postAs('admin', "I won't delete this")
let reply = await postReplyAs('admin', 'But I will delete this', status.id)
await t.expect(getNthStatus(0).innerText).contains('But I will delete this', { timeout })
.expect(getNthStatus(1).innerText).contains("I won't delete this", { timeout })
.click(getNthStatus(1))
await t.expect(getNthStatus(1).innerText).contains('But I will delete this', { timeout })
.expect(getNthStatus(2).innerText).contains("I won't delete this", { timeout })
.click(getNthStatus(2))
.expect(getUrl()).contains('/statuses')
.expect(getNthStatus(0).innerText).contains("I won't delete this", { timeout })
.expect(getNthStatus(1).innerText).contains('But I will delete this', { timeout })
.expect(getNthStatus(1).innerText).contains("I won't delete this", { timeout })
.expect(getNthStatus(2).innerText).contains('But I will delete this', { timeout })
await deleteAs('admin', reply.id)
await t.expect(getNthStatus(1).exists).notOk()
.expect(getNthStatus(0).innerText).contains("I won't delete this", { timeout })
await t.expect(getNthStatus(2).exists).notOk()
.expect(getNthStatus(1).innerText).contains("I won't delete this", { timeout })
await t.navigateTo('/')
await forceOffline()
await t.click(getNthStatus(0))
await t.click(getNthStatus(1))
.expect(getUrl()).contains('/statuses')
.expect(getNthStatus(1).exists).notOk()
.expect(getNthStatus(0).innerText).contains("I won't delete this", { timeout })
.expect(getNthStatus(2).exists).notOk()
.expect(getNthStatus(1).innerText).contains("I won't delete this", { timeout })
await forceOnline()
})
@ -58,7 +58,7 @@ test('deleted statuses result in deleted notifications', async t => {
let timeout = 20000
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.hover(getNthStatus(1))
.expect(notificationsNavButton.getAttribute('aria-label')).eql('Notifications')
let status = await postAs('admin', "@foobar yo yo foobar what's up")
await t.expect(notificationsNavButton.getAttribute('aria-label')).eql('Notifications (1 notification)', { timeout })

View file

@ -30,7 +30,7 @@ test('can request to follow an account', async t => {
await t.navigateTo('/accounts/6')
.expect(accountProfileFollowButton.getAttribute('aria-label')).eql('Unfollow')
.expect(getNthStatus(0).innerText).contains('This account is locked')
.expect(getNthStatus(1).innerText).contains('This account is locked')
.click(accountProfileFollowButton)
.expect(accountProfileFollowButton.getAttribute('aria-label')).eql('Follow')
})

View file

@ -15,18 +15,18 @@ test('fills in a status posted while away from timeline', async t => {
await loginAsFoobar(t)
await t
.click(localTimelineNavButton)
.expect(getNthStatus(0).exists).ok({ timeout })
.hover(getNthStatus(0))
.expect(getNthStatus(1).exists).ok({ timeout })
.hover(getNthStatus(1))
await postAs('admin', 'heyo')
await t.expect(getNthStatus(0).innerText).contains('heyo', { timeout })
await t.expect(getNthStatus(1).innerText).contains('heyo', { timeout })
.click(homeNavButton)
.hover(getNthStatus(0))
.hover(getNthStatus(1))
await postAs('admin', 'posted this while you were away!')
await t.expect(getNthStatus(0).innerText).contains('posted this while you were away!', { timeout })
await t.expect(getNthStatus(1).innerText).contains('posted this while you were away!', { timeout })
.click(localTimelineNavButton)
.expect(getNthStatus(0).innerText).contains('posted this while you were away!', { timeout })
.expect(getNthStatus(1).innerText).contains('heyo', { timeout })
.expect(getNthStatus(1).innerText).contains('posted this while you were away!', { timeout })
.expect(getNthStatus(2).innerText).contains('heyo', { timeout })
await sleep(5000)
await postAs('admin', 'posted this while you were watching')
await t.expect(getNthStatus(0).innerText).contains('posted this while you were watching', { timeout })
await t.expect(getNthStatus(1).innerText).contains('posted this while you were watching', { timeout })
})

View file

@ -19,7 +19,7 @@ fixture`108-compose-dialog.js`
test('can compose using a dialog', async t => {
await loginAsFoobar(t)
await scrollToStatus(t, 15)
await scrollToStatus(t, 16)
await t.expect(modalDialog.exists).notOk()
.expect(composeButton.getAttribute('aria-label')).eql('Compose')
await sleep(2000)
@ -31,13 +31,13 @@ test('can compose using a dialog', async t => {
.click(notificationsNavButton)
.expect(getUrl()).contains('/notifications')
.navigateTo('/')
.hover(getNthStatus(0))
.expect(getNthStatus(0).innerText).contains('hello from the modal', { timeout: 20000 })
.hover(getNthStatus(1))
.expect(getNthStatus(1).innerText).contains('hello from the modal', { timeout: 20000 })
})
test('can use emoji dialog within compose dialog', async t => {
await loginAsFoobar(t)
await scrollToStatus(t, 15)
await scrollToStatus(t, 16)
await t.expect(composeButton.getAttribute('aria-label')).eql('Compose')
await sleep(2000)
await t.click(composeButton)
@ -50,5 +50,5 @@ test('can use emoji dialog within compose dialog', async t => {
.click(notificationsNavButton)
.expect(getUrl()).contains('/notifications')
.navigateTo('/')
await t.expect($(`${getNthStatusSelector(0)} img[alt=":blobpats:"]`).exists).ok({ timeout: 20000 })
await t.expect($(`${getNthStatusSelector(1)} img[alt=":blobpats:"]`).exists).ok({ timeout: 20000 })
})

View file

@ -25,10 +25,10 @@ test('uploads alts for media', async t => {
await t.typeText(getNthMediaAltInput(2), 'kitten 2')
.typeText(getNthMediaAltInput(1), 'kitten 1')
.click(composeButton)
.expect(getNthStatusAndImage(0, 0).getAttribute('alt')).eql('kitten 1')
.expect(getNthStatusAndImage(0, 0).getAttribute('title')).eql('kitten 1')
.expect(getNthStatusAndImage(0, 1).getAttribute('alt')).eql('kitten 2')
.expect(getNthStatusAndImage(0, 1).getAttribute('title')).eql('kitten 2')
.expect(getNthStatusAndImage(1, 0).getAttribute('alt')).eql('kitten 1')
.expect(getNthStatusAndImage(1, 0).getAttribute('title')).eql('kitten 1')
.expect(getNthStatusAndImage(1, 1).getAttribute('alt')).eql('kitten 2')
.expect(getNthStatusAndImage(1, 1).getAttribute('title')).eql('kitten 2')
})
test('uploads alts when deleting and re-uploading media', async t => {
@ -44,7 +44,7 @@ test('uploads alts when deleting and re-uploading media', async t => {
.expect(getNthMedia(1).getAttribute('alt')).eql('kitten2.jpg')
.typeText(getNthMediaAltInput(1), 'this will not be deleted')
.click(composeButton)
.expect(getNthStatusAndImage(0, 0).getAttribute('alt')).eql('this will not be deleted')
.expect(getNthStatusAndImage(1, 0).getAttribute('alt')).eql('this will not be deleted')
})
test('uploads alts mixed with no-alts', async t => {
@ -54,8 +54,8 @@ test('uploads alts mixed with no-alts', async t => {
await uploadTwoKittens(t)
await t.typeText(getNthMediaAltInput(2), 'kitten numero dos')
.click(composeButton)
.expect(getNthStatusAndImage(0, 0).getAttribute('alt')).eql('')
.expect(getNthStatusAndImage(0, 1).getAttribute('alt')).eql('kitten numero dos')
.expect(getNthStatusAndImage(1, 0).getAttribute('alt')).eql('')
.expect(getNthStatusAndImage(1, 1).getAttribute('alt')).eql('kitten numero dos')
})
test('saves alts to local storage', async t => {
@ -74,8 +74,8 @@ test('saves alts to local storage', async t => {
.expect(getNthMediaAltInput(1).value).eql('kitten numero uno')
.expect(getNthMediaAltInput(2).value).eql('kitten numero dos')
.click(composeButton)
.expect(getNthStatusAndImage(0, 0).getAttribute('alt')).eql('kitten numero uno')
.expect(getNthStatusAndImage(0, 1).getAttribute('alt')).eql('kitten numero dos')
.expect(getNthStatusAndImage(1, 0).getAttribute('alt')).eql('kitten numero uno')
.expect(getNthStatusAndImage(1, 1).getAttribute('alt')).eql('kitten numero dos')
})
test('can post a status with empty content if there is media', async t => {
@ -87,5 +87,5 @@ test('can post a status with empty content if there is media', async t => {
await t
.typeText(getNthMediaAltInput(1), 'just an image!')
await t.click(composeButton)
.expect(getNthStatusAndImage(0, 0).getAttribute('alt')).eql('just an image!')
.expect(getNthStatusAndImage(1, 0).getAttribute('alt')).eql('just an image!')
})

View file

@ -15,11 +15,11 @@ test('content warnings are posted', async t => {
.click(contentWarningButton)
.typeText(composeContentWarning, 'CW', { paste: true })
.click(composeButton)
.expect($(`${getNthStatusSelector(0)} .status-spoiler`).innerText).contains('CW', { timeout: 30000 })
.click(getNthShowOrHideButton(0))
.expect($(`${getNthStatusSelector(0)} .status-content`).innerText).contains('hello this is a toot')
.click(getNthShowOrHideButton(0))
.expect(getNthStatus(0).innerText).notContains('hello this is a toot')
.expect($(`${getNthStatusSelector(1)} .status-spoiler`).innerText).contains('CW', { timeout: 30000 })
.click(getNthShowOrHideButton(1))
.expect($(`${getNthStatusSelector(1)} .status-content`).innerText).contains('hello this is a toot')
.click(getNthShowOrHideButton(1))
.expect(getNthStatus(1).innerText).notContains('hello this is a toot')
})
test('content warnings are not posted if removed', async t => {
@ -31,9 +31,9 @@ test('content warnings are not posted if removed', async t => {
.click(contentWarningButton)
.expect(composeContentWarning.exists).notOk()
.click(composeButton)
.expect(getNthStatus(0).innerText).contains('hi this is another toot', { timeout: 30000 })
.expect(getNthStatus(0).innerText).notContains('content warning!')
.expect($(`${getNthStatusSelector(0)} .status-content`).innerText).contains('hi this is another toot')
.expect(getNthStatus(1).innerText).contains('hi this is another toot', { timeout: 30000 })
.expect(getNthStatus(1).innerText).notContains('content warning!')
.expect($(`${getNthStatusSelector(1)} .status-content`).innerText).contains('hi this is another toot')
})
test('content warnings can have emoji', async t => {
@ -43,10 +43,10 @@ test('content warnings can have emoji', async t => {
.click(contentWarningButton)
.typeText(composeContentWarning, 'can you feel the :blobpats: tonight')
.click(composeButton)
.expect(getNthStatus(0).innerText).contains('can you feel the', { timeout: 30000 })
.expect($(`${getNthStatusSelector(0)} .status-spoiler img.inline-custom-emoji`).getAttribute('alt')).eql(':blobpats:')
.click(getNthShowOrHideButton(0))
.expect($(`${getNthStatusSelector(0)} .status-content img.inline-custom-emoji`).getAttribute('alt')).eql(':blobnom:')
.expect(getNthStatus(1).innerText).contains('can you feel the', { timeout: 30000 })
.expect($(`${getNthStatusSelector(1)} .status-spoiler img.inline-custom-emoji`).getAttribute('alt')).eql(':blobpats:')
.click(getNthShowOrHideButton(1))
.expect($(`${getNthStatusSelector(1)} .status-content img.inline-custom-emoji`).getAttribute('alt')).eql(':blobnom:')
})
test('no XSS in content warnings or text', async t => {
@ -58,7 +58,7 @@ test('no XSS in content warnings or text', async t => {
.click(contentWarningButton)
.typeText(composeContentWarning, pwned2)
.click(composeButton)
.expect($(`${getNthStatusSelector(0)} .status-spoiler`).innerText).contains(pwned2)
.click(getNthShowOrHideButton(0))
.expect($(`${getNthStatusSelector(0)} .status-content`).innerText).contains(pwned1)
.expect($(`${getNthStatusSelector(1)} .status-spoiler`).innerText).contains(pwned2)
.click(getNthShowOrHideButton(1))
.expect($(`${getNthStatusSelector(1)} .status-content`).innerText).contains(pwned1)
})

View file

@ -15,9 +15,9 @@ test('replying to a toot returns focus to reply button', async t => {
await t
.typeText(composeInput, 'I would like, if I may, to take you on a strange journey', { paste: true })
.pressKey('ctrl+enter')
.expect($(`${getNthStatusSelector(0)} .status-content`).innerText).contains('I would like, if I may, to take you on a strange journey')
.click(getNthReplyButton(0))
.typeText(getNthComposeReplyInput(0), 'How strange was it?', { paste: true })
.click(getNthComposeReplyButton(0))
.expect($(`${getNthStatusSelector(1)} .status-content`).innerText).contains('I would like, if I may, to take you on a strange journey')
.click(getNthReplyButton(1))
.typeText(getNthComposeReplyInput(1), 'How strange was it?', { paste: true })
.click(getNthComposeReplyButton(1))
.expect(getActiveElementClassList()).contains('status-toolbar-reply-button', { timeout: 20000 })
})

View file

@ -15,13 +15,13 @@ test('External links, hashtags, and mentions have correct attributes', async t =
'and also http://example.com and https://joinmastodon.org and ' +
'https://mastodon.social.'
const nthAnchor = n => $(`${getNthStatusSelector(0)} .status-content a`).nth(n)
const nthAnchor = n => $(`${getNthStatusSelector(1)} .status-content a`).nth(n)
await loginAsFoobar(t)
await t
.typeText(composeInput, text, { paste: true })
.click(composeButton)
.expect(getNthStatus(0).innerText).contains('Why hello there', { timeout: 20000 })
.expect(getNthStatus(1).innerText).contains('Why hello there', { timeout: 20000 })
.expect(nthAnchor(0).getAttribute('href')).eql('/accounts/1')
.expect(nthAnchor(0).hasAttribute('rel')).notOk()
.expect(nthAnchor(0).getAttribute('title')).eql('@admin')

View file

@ -15,8 +15,8 @@ test('Can block and unblock an account from a status', async t => {
await postAs('admin', post)
await loginAsFoobar(t)
await t
.expect(getNthStatus(0).innerText).contains(post, { timeout: 30000 })
.click(getNthStatusOptionsButton(0))
.expect(getNthStatus(1).innerText).contains(post, { timeout: 30000 })
.click(getNthStatusOptionsButton(1))
.expect(getNthDialogOptionsOption(1).innerText).contains('Unfollow @admin')
.expect(getNthDialogOptionsOption(2).innerText).contains('Block @admin')
.click(getNthDialogOptionsOption(2))

View file

@ -23,8 +23,8 @@ test('Can mute and unmute an account', async t => {
let post = 'blah blah blah'
await postAs('admin', post)
await t.expect(getNthStatus(0).innerText).contains(post, { timeout: 20000 })
.click(getNthStatusOptionsButton(0))
await t.expect(getNthStatus(1).innerText).contains(post, { timeout: 20000 })
.click(getNthStatusOptionsButton(1))
.expect(getNthDialogOptionsOption(1).innerText).contains('Unfollow @admin')
.expect(getNthDialogOptionsOption(2).innerText).contains('Block @admin')
.expect(getNthDialogOptionsOption(3).innerText).contains('Mute @admin')

View file

@ -17,40 +17,40 @@ test('Can pin statuses', async t => {
await t
.typeText(composeInput, 'I am going to pin this', { paste: true })
.click(postStatusButton)
.expect(getNthStatus(0).innerText).contains('I am going to pin this')
.expect(getNthStatus(1).innerText).contains('I am going to pin this')
.click(avatarInComposeBox)
.expect(getUrl()).contains(`/accounts/${users.foobar.id}`)
.expect(getNthPinnedStatus(0).getAttribute('aria-setsize')).eql('1')
.expect(getNthPinnedStatus(0).innerText).contains('this is unlisted')
.expect(getNthStatus(0).innerText).contains('I am going to pin this')
.click(getNthStatusOptionsButton(0))
.expect(getNthPinnedStatus(1).getAttribute('aria-setsize')).eql('1')
.expect(getNthPinnedStatus(1).innerText).contains('this is unlisted')
.expect(getNthStatus(1).innerText).contains('I am going to pin this')
.click(getNthStatusOptionsButton(1))
.expect(getNthDialogOptionsOption(1).innerText).contains('Delete')
.expect(getNthDialogOptionsOption(2).innerText).contains('Pin to profile')
.click(getNthDialogOptionsOption(2))
.expect(getNthPinnedStatus(0).getAttribute('aria-setsize')).eql('2')
.expect(getNthPinnedStatus(0).innerText).contains('I am going to pin this')
.expect(getNthPinnedStatus(1).innerText).contains('this is unlisted')
.expect(getNthStatus(0).innerText).contains('I am going to pin this')
.click(getNthStatusOptionsButton(0))
.expect(getNthPinnedStatus(1).getAttribute('aria-setsize')).eql('2')
.expect(getNthPinnedStatus(1).innerText).contains('I am going to pin this')
.expect(getNthPinnedStatus(2).innerText).contains('this is unlisted')
.expect(getNthStatus(1).innerText).contains('I am going to pin this')
.click(getNthStatusOptionsButton(1))
.expect(getNthDialogOptionsOption(1).innerText).contains('Delete')
.expect(getNthDialogOptionsOption(2).innerText).contains('Unpin from profile')
.click(getNthDialogOptionsOption(2))
.expect(getUrl()).contains(`/accounts/${users.foobar.id}`)
.expect(getNthPinnedStatus(0).getAttribute('aria-setsize')).eql('1')
.expect(getNthPinnedStatus(0).innerText).contains('this is unlisted')
.expect(getNthStatus(0).innerText).contains('I am going to pin this')
.expect(getNthPinnedStatus(1).getAttribute('aria-setsize')).eql('1')
.expect(getNthPinnedStatus(1).innerText).contains('this is unlisted')
.expect(getNthStatus(1).innerText).contains('I am going to pin this')
})
test('Can favorite a pinned status', async t => {
await loginAsFoobar(t)
await t
.click(avatarInComposeBox)
.expect(getNthPinnedStatus(0).getAttribute('aria-setsize')).eql('1')
.expect(getNthPinnedStatusFavoriteButton(0).getAttribute('aria-pressed')).eql('false')
.click(getNthPinnedStatusFavoriteButton(0))
.expect(getNthPinnedStatusFavoriteButton(0).getAttribute('aria-pressed')).eql('true')
.click(getNthPinnedStatusFavoriteButton(0))
.expect(getNthPinnedStatusFavoriteButton(0).getAttribute('aria-pressed')).eql('false')
.expect(getNthPinnedStatus(1).getAttribute('aria-setsize')).eql('1')
.expect(getNthPinnedStatusFavoriteButton(1).getAttribute('aria-pressed')).eql('false')
.click(getNthPinnedStatusFavoriteButton(1))
.expect(getNthPinnedStatusFavoriteButton(1).getAttribute('aria-pressed')).eql('true')
.click(getNthPinnedStatusFavoriteButton(1))
.expect(getNthPinnedStatusFavoriteButton(1).getAttribute('aria-pressed')).eql('false')
})
test('Saved pinned/unpinned state of status', async t => {
@ -58,13 +58,13 @@ test('Saved pinned/unpinned state of status', async t => {
await postAs('foobar', 'hey I am going to pin and unpin this')
await loginAsFoobar(t)
await t
.expect(getNthStatusContent(0).innerText).contains('hey I am going to pin and unpin this', { timeout })
.click(getNthStatusOptionsButton(0))
.expect(getNthStatusContent(1).innerText).contains('hey I am going to pin and unpin this', { timeout })
.click(getNthStatusOptionsButton(1))
.expect(getNthDialogOptionsOption(2).innerText).contains('Pin to profile')
.click(getNthDialogOptionsOption(2))
await sleep(1)
await t
.click(getNthStatusOptionsButton(0))
.click(getNthStatusOptionsButton(1))
.expect(getNthDialogOptionsOption(2).innerText).contains('Unpin from profile')
.click(closeDialogButton)
@ -74,13 +74,13 @@ test('Saved pinned/unpinned state of status', async t => {
await scrollToTop()
await t
.expect(getNthStatusContent(0).innerText).contains('hey I am going to pin and unpin this', { timeout })
.click(getNthStatusOptionsButton(0))
.expect(getNthStatusContent(1).innerText).contains('hey I am going to pin and unpin this', { timeout })
.click(getNthStatusOptionsButton(1))
.expect(getNthDialogOptionsOption(2).innerText).contains('Unpin from profile', { timeout })
// navigate to another page and back to force another unrender
.click(settingsNavButton)
.click(homeNavButton)
.expect(getNthStatusContent(0).innerText).contains('hey I am going to pin and unpin this', { timeout })
.click(getNthStatusOptionsButton(0))
.expect(getNthStatusContent(1).innerText).contains('hey I am going to pin and unpin this', { timeout })
.click(getNthStatusOptionsButton(1))
.expect(getNthDialogOptionsOption(2).innerText).contains('Unpin from profile', { timeout })
})

View file

@ -26,7 +26,7 @@ test('Can put custom emoji in display name', async t => {
.expect($('.compose-box-display-name img').getAttribute('alt')).eql(':blobpats:')
.click(displayNameInComposeBox)
.expect(getUrl()).contains('/accounts/2')
.expect($(`${getNthStatusSelector(0)} .status-author-name img`).getAttribute('alt')).eql(':blobpats:')
.expect($(`${getNthStatusSelector(1)} .status-author-name img`).getAttribute('alt')).eql(':blobpats:')
})
test('Cannot XSS using display name HTML', async t => {
@ -97,7 +97,7 @@ test('Check status aria labels for de-emojified text', async t => {
await loginAsFoobar(t)
await t
.click(displayNameInComposeBox)
.expect(getNthStatus(0).getAttribute('aria-label')).match(
.expect(getNthStatus(1).getAttribute('aria-label')).match(
new RegExp(`${rainbow} foo :blobpats: ${rainbow}, hey ho lotsa emojos, (.* ago|just now), @foobar, Public`, 'i')
)
.click(settingsNavButton)
@ -106,7 +106,7 @@ test('Check status aria labels for de-emojified text', async t => {
.expect(removeEmojiFromDisplayNamesInput.checked).ok()
.click(homeNavButton)
.click(displayNameInComposeBox)
.expect(getNthStatus(0).getAttribute('aria-label')).match(
.expect(getNthStatus(1).getAttribute('aria-label')).match(
new RegExp(`foo, hey ho lotsa emojos, (.* ago|just now), @foobar, Public`, 'i')
)
.click(settingsNavButton)
@ -115,7 +115,7 @@ test('Check status aria labels for de-emojified text', async t => {
.expect(removeEmojiFromDisplayNamesInput.checked).notOk()
.click(homeNavButton)
.click(displayNameInComposeBox)
.expect(getNthStatus(0).getAttribute('aria-label')).match(
.expect(getNthStatus(1).getAttribute('aria-label')).match(
new RegExp(`${rainbow} foo :blobpats: ${rainbow}, hey ho lotsa emojos, (.* ago|just now), @foobar, Public`, 'i')
)
})

View file

@ -14,23 +14,23 @@ test('Fav stats update', async t => {
await favoriteStatusAs('admin', statusId)
await loginAsFoobar(t)
await t
.expect(getNthStatusContent(0).innerText).contains('hey hello look at this toot')
.click(getNthStatus(0))
.expect(getNthStatusContent(1).innerText).contains('hey hello look at this toot')
.click(getNthStatus(1))
.expect(getFavoritesCount()).eql(1)
.click(homeNavButton)
await favoriteStatusAs('quux', statusId)
await t
.click(getNthStatus(0))
.click(getNthStatus(1))
.expect(getFavoritesCount()).eql(2)
.click(homeNavButton)
await favoriteStatusAs('baz', statusId)
await t
.click(getNthStatus(0))
.click(getNthStatus(1))
.expect(getFavoritesCount()).eql(3)
.click(homeNavButton)
await favoriteStatusAs('LockedAccount', statusId)
await t
.click(getNthStatus(0))
.click(getNthStatus(1))
.expect(getFavoritesCount()).eql(4)
})
@ -40,23 +40,23 @@ test('Reblog stats update', async t => {
await reblogStatusAs('admin', statusId)
await loginAsFoobar(t)
await t
.expect(getNthStatusContent(0).innerText).contains('oh why hello it looks like another toot')
.click(getNthStatus(0))
.expect(getNthStatusContent(1).innerText).contains('oh why hello it looks like another toot')
.click(getNthStatus(1))
.expect(getReblogsCount()).eql(1)
.click(homeNavButton)
await reblogStatusAs('quux', statusId)
await t
.click(getNthStatus(0))
.click(getNthStatus(1))
.expect(getReblogsCount()).eql(2)
.click(homeNavButton)
await reblogStatusAs('baz', statusId)
await t
.click(getNthStatus(0))
.click(getNthStatus(1))
.expect(getReblogsCount()).eql(3)
.click(homeNavButton)
await reblogStatusAs('LockedAccount', statusId)
await t
.click(getNthStatus(0))
.click(getNthStatus(1))
.expect(getReblogsCount()).eql(4)
})
@ -68,20 +68,20 @@ test('Fav and reblog stats update for a boosted toot', async t => {
await favoriteStatusAs('quux', statusId)
await loginAsFoobar(t)
await t
.expect(getNthStatusContent(0).innerText).contains('this will get boosted')
.click(getNthStatus(0))
.expect(getNthStatusContent(1).innerText).contains('this will get boosted')
.click(getNthStatus(1))
.expect(getReblogsCount()).eql(1)
.expect(getFavoritesCount()).eql(2)
.click(homeNavButton)
await favoriteStatusAs('baz', statusId)
await t
.click(getNthStatus(0))
.click(getNthStatus(1))
.expect(getReblogsCount()).eql(1)
.expect(getFavoritesCount()).eql(3)
.click(homeNavButton)
await favoriteStatusAs('LockedAccount', statusId)
await t
.click(getNthStatus(0))
.click(getNthStatus(1))
.expect(getReblogsCount()).eql(1)
.expect(getFavoritesCount()).eql(4)
})

View file

@ -9,8 +9,8 @@ test('aria-labels for statuses with no content text', async t => {
await postEmptyStatusWithMediaAs('foobar', 'kitten1.jpg', 'kitteh')
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.expect(getNthStatus(0).getAttribute('aria-label')).match(
.hover(getNthStatus(1))
.expect(getNthStatus(1).getAttribute('aria-label')).match(
/foobar, (.+ ago|just now), @foobar, Public/i
)
})

View file

@ -24,9 +24,9 @@ test('basic delete and redraft', async t => {
await postAs('foobar', 'hey ho this is grate')
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.expect(getNthStatusContent(0).innerText).contains('hey ho this is grate')
.click(getNthStatusOptionsButton(0))
.hover(getNthStatus(1))
.expect(getNthStatusContent(1).innerText).contains('hey ho this is grate')
.click(getNthStatusOptionsButton(1))
.click(dialogOptionsOption.withText('Delete and redraft'))
.expect(modalDialog.hasAttribute('aria-hidden')).notOk()
.expect(composeModalInput.value).contains('hey ho this is grate')
@ -34,16 +34,16 @@ test('basic delete and redraft', async t => {
.typeText(composeModalInput, 'hey ho this is great', { replace: true, paste: true })
.click(composeModalComposeButton)
.expect(modalDialog.exists).notOk()
.expect(getNthStatusContent(0).innerText).contains('hey ho this is great')
.expect(getNthStatusContent(1).innerText).contains('hey ho this is great')
})
test('image with empty text delete and redraft', async t => {
await postEmptyStatusWithMediaAs('foobar', 'kitten2.jpg', 'what a kitteh')
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.expect(getNthStatusMediaImg(0).getAttribute('alt')).eql('what a kitteh')
.click(getNthStatusOptionsButton(0))
.hover(getNthStatus(1))
.expect(getNthStatusMediaImg(1).getAttribute('alt')).eql('what a kitteh')
.click(getNthStatusOptionsButton(1))
.click(dialogOptionsOption.withText('Delete and redraft'))
.expect(modalDialog.hasAttribute('aria-hidden')).notOk()
.expect(composeModalInput.value).eql('')
@ -53,17 +53,17 @@ test('image with empty text delete and redraft', async t => {
.typeText(composeModalInput, 'I love this kitteh', { replace: true, paste: true })
.click(composeModalComposeButton)
.expect(modalDialog.exists).notOk()
.expect(getNthStatusContent(0).innerText).contains('I love this kitteh')
.expect(getNthStatusMediaImg(0).getAttribute('alt')).eql('what a kitteh')
.expect(getNthStatusContent(1).innerText).contains('I love this kitteh')
.expect(getNthStatusMediaImg(1).getAttribute('alt')).eql('what a kitteh')
})
test('image with no alt delete and redraft', async t => {
await postEmptyStatusWithMediaAs('foobar', 'kitten3.jpg', '')
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.expect(getNthStatusMediaImg(0).getAttribute('alt')).eql('')
.click(getNthStatusOptionsButton(0))
.hover(getNthStatus(1))
.expect(getNthStatusMediaImg(1).getAttribute('alt')).eql('')
.click(getNthStatusOptionsButton(1))
.click(dialogOptionsOption.withText('Delete and redraft'))
.expect(modalDialog.hasAttribute('aria-hidden')).notOk()
.expect(composeModalInput.value).eql('')
@ -74,17 +74,17 @@ test('image with no alt delete and redraft', async t => {
.typeText(getComposeModalNthMediaAltInput(1), 'lovely kitteh', { replace: true, paste: true })
.click(composeModalComposeButton)
.expect(modalDialog.exists).notOk()
.expect(getNthStatusContent(0).innerText).contains('oops forgot an alt')
.expect(getNthStatusMediaImg(0).getAttribute('alt')).eql('lovely kitteh')
.expect(getNthStatusContent(1).innerText).contains('oops forgot an alt')
.expect(getNthStatusMediaImg(1).getAttribute('alt')).eql('lovely kitteh')
})
test('privacy and spoiler delete and redraft', async t => {
await postWithSpoilerAndPrivacyAs('foobar', 'this is hidden', 'click to see!', 'private')
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.expect(getNthStatusSpoiler(0).innerText).contains('click to see!')
.click(getNthStatusOptionsButton(0))
.hover(getNthStatus(1))
.expect(getNthStatusSpoiler(1).innerText).contains('click to see!')
.click(getNthStatusOptionsButton(1))
.click(dialogOptionsOption.withText('Delete and redraft'))
.expect(modalDialog.hasAttribute('aria-hidden')).notOk()
.expect(composeModalInput.value).eql('this is hidden')
@ -93,57 +93,57 @@ test('privacy and spoiler delete and redraft', async t => {
.typeText(composeModalContentWarningInput, 'no really, you should click this!', { replace: true, paste: true })
.click(composeModalComposeButton)
.expect(modalDialog.exists).notOk()
.expect(getNthStatusSpoiler(0).innerText).contains('no really, you should click this!')
.expect(getNthStatusSpoiler(1).innerText).contains('no really, you should click this!')
})
test('delete and redraft reply', async t => {
await postAs('admin', 'hey hello')
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.expect(getNthStatusContent(0).innerText).contains('hey hello')
.click(getNthReplyButton(0))
.typeText(getNthComposeReplyInput(0), 'hello there admin', { paste: true })
.click(getNthComposeReplyButton(0))
.expect(getNthStatus(0).innerText).contains('@admin hello there admin')
.click(getNthStatusOptionsButton(0))
.hover(getNthStatus(1))
.expect(getNthStatusContent(1).innerText).contains('hey hello')
.click(getNthReplyButton(1))
.typeText(getNthComposeReplyInput(1), 'hello there admin', { paste: true })
.click(getNthComposeReplyButton(1))
.expect(getNthStatus(1).innerText).contains('@admin hello there admin')
.click(getNthStatusOptionsButton(1))
.click(dialogOptionsOption.withText('Delete and redraft'))
.expect(modalDialog.hasAttribute('aria-hidden')).notOk()
.typeText(composeModalInput, ' oops forgot to say thank you')
.click(composeModalComposeButton)
.expect(modalDialog.exists).notOk()
.expect(getNthStatusContent(0).innerText).match(/@admin hello there admin\s+oops forgot to say thank you/, {
.expect(getNthStatusContent(1).innerText).match(/@admin hello there admin\s+oops forgot to say thank you/, {
timeout: 30000
})
.click(getNthStatus(0))
.click(getNthStatus(1))
.expect(getUrl()).match(/statuses/)
.expect(getNthStatusContent(0).innerText).contains('hey hello')
.expect(getNthStatusContent(1).innerText).match(/@admin hello there admin\s+oops forgot to say thank you/)
.expect(getNthStatusContent(1).innerText).contains('hey hello')
.expect(getNthStatusContent(2).innerText).match(/@admin hello there admin\s+oops forgot to say thank you/)
})
test('delete and redraft reply within thread', async t => {
await postAs('admin', 'this is a thread')
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.expect(getNthStatusContent(0).innerText).contains('this is a thread')
.click(getNthStatus(0))
.hover(getNthStatus(1))
.expect(getNthStatusContent(1).innerText).contains('this is a thread')
.click(getNthStatus(1))
.expect(getUrl()).match(/statuses/)
.expect(getNthStatusContent(0).innerText).contains('this is a thread')
.click(getNthReplyButton(0))
.typeText(getNthComposeReplyInput(0), 'heyo', { paste: true })
.click(getNthComposeReplyButton(0))
.expect(getNthStatus(1).innerText).contains('@admin heyo')
.click(getNthStatusOptionsButton(1))
.expect(getNthStatusContent(1).innerText).contains('this is a thread')
.click(getNthReplyButton(1))
.typeText(getNthComposeReplyInput(1), 'heyo', { paste: true })
.click(getNthComposeReplyButton(1))
.expect(getNthStatus(2).innerText).contains('@admin heyo')
.click(getNthStatusOptionsButton(2))
.click(dialogOptionsOption.withText('Delete and redraft'))
.expect(modalDialog.hasAttribute('aria-hidden')).notOk()
.typeText(composeModalInput, ' update!', { paste: true })
.click(composeModalComposeButton)
.expect(modalDialog.exists).notOk()
.expect(getNthStatusContent(1).innerText).match(/@admin heyo\s+update!/, {
.expect(getNthStatusContent(2).innerText).match(/@admin heyo\s+update!/, {
timeout: 30000
})
.expect(getNthStatus(2).exists).notOk()
.expect(getNthStatus(3).exists).notOk()
})
test('multiple paragraphs', async t => {
@ -151,14 +151,14 @@ test('multiple paragraphs', async t => {
await postAs('foobar', text)
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.expect(getNthStatusContent(0).innerText).contains(text)
.click(getNthStatusOptionsButton(0))
.hover(getNthStatus(1))
.expect(getNthStatusContent(1).innerText).contains(text)
.click(getNthStatusOptionsButton(1))
.click(dialogOptionsOption.withText('Delete and redraft'))
.expect(modalDialog.hasAttribute('aria-hidden')).notOk()
.expect(composeModalInput.value).eql(text)
.typeText(composeModalInput, '\n\nwoot', { paste: true })
.click(composeModalComposeButton)
.expect(modalDialog.exists).notOk()
.expect(getNthStatusContent(0).innerText).contains(text + '\n\nwoot')
.expect(getNthStatusContent(1).innerText).contains(text + '\n\nwoot')
})

View file

@ -37,13 +37,13 @@ test('reply to non-focused parent status in a thread', async t => {
await postReplyAs('admin', 'and here it is continued', id)
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.expect(getNthStatusContent(0).innerText).contains('and here it is continued')
.click(getNthStatus(0))
.hover(getNthStatus(1))
.expect(getNthStatusContent(1).innerText).contains('and here it is continued')
.click(getNthStatus(1))
.expect(getUrl()).match(/statuses/)
.click(getNthReplyButton(0))
.typeText(getNthComposeReplyInput(0), 'haha I totally agree', { paste: true })
.click(getNthComposeReplyButton(0))
.click(getNthReplyButton(1))
.typeText(getNthComposeReplyInput(1), 'haha I totally agree', { paste: true })
.click(getNthComposeReplyButton(1))
await verifyAriaSetSize(t, '2')
})
@ -53,14 +53,14 @@ test('reply to focused status in a thread', async t => {
await postReplyAs('admin', 'whoa and here it is probably continued', id)
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.expect(getNthStatusContent(0).innerText).contains('whoa and here it is probably continued')
.hover(getNthStatusContent(1))
.click(getNthStatus(1))
.hover(getNthStatus(1))
.expect(getNthStatusContent(1).innerText).contains('whoa and here it is probably continued')
.hover(getNthStatusContent(2))
.click(getNthStatus(2))
.expect(getUrl()).match(/statuses/)
.click(getNthReplyButton(0))
.typeText(getNthComposeReplyInput(0), 'haha I totally agree', { paste: true })
.click(getNthComposeReplyButton(0))
.click(getNthReplyButton(1))
.typeText(getNthComposeReplyInput(1), 'haha I totally agree', { paste: true })
.click(getNthComposeReplyButton(1))
await verifyAriaSetSize(t, '3')
})
@ -72,16 +72,16 @@ test('reply to non-focused grandparent status in a thread', async t => {
await postReplyAs('admin', 'cool thread 3/3', id2)
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.expect(getNthStatusContent(0).innerText).contains('cool thread 3/3')
.click(getNthStatus(0))
.hover(getNthStatus(1))
.expect(getNthStatusContent(1).innerText).contains('cool thread 3/3')
.click(getNthStatus(1))
.expect(getUrl()).match(/statuses/)
.hover(getNthStatus(3))
.hover(getNthStatus(2))
.hover(getNthStatus(1))
.hover(getNthStatus(0))
.click(getNthReplyButton(0))
.typeText(getNthComposeReplyInput(0), 'this is sweet', { paste: true })
.click(getNthComposeReplyButton(0))
.click(getNthReplyButton(1))
.typeText(getNthComposeReplyInput(1), 'this is sweet', { paste: true })
.click(getNthComposeReplyButton(1))
await verifyAriaSetSize(t, '3')
})
@ -92,17 +92,17 @@ test('reply to non-focused grandchild status in a thread', async t => {
await postReplyAs('admin', 'sweet thread 3/3', id2)
await loginAsFoobar(t)
await t
.hover(getNthStatus(0))
.expect(getNthStatusContent(0).innerText).contains('sweet thread 3/3')
.hover(getNthStatusContent(1))
.hover(getNthStatus(2))
.click(getNthStatus(2))
.hover(getNthStatus(1))
.expect(getNthStatusContent(1).innerText).contains('sweet thread 3/3')
.hover(getNthStatusContent(2))
.hover(getNthStatus(3))
.click(getNthStatus(3))
.expect(getUrl()).match(/statuses/)
.hover(getNthStatus(0))
.hover(getNthStatus(1))
.hover(getNthStatus(2))
.click(getNthReplyButton(2))
.typeText(getNthComposeReplyInput(2), 'this is sweet', { paste: true })
.click(getNthComposeReplyButton(2))
.hover(getNthStatus(3))
.click(getNthReplyButton(3))
.typeText(getNthComposeReplyInput(3), 'this is sweet', { paste: true })
.click(getNthComposeReplyButton(3))
await verifyAriaSetSize(t, '4')
})

View file

@ -216,7 +216,7 @@ export function getNthDeleteMediaButton (n) {
}
export function getAriaSetSize () {
return getNthStatus(0).getAttribute('aria-setsize')
return getNthStatus(1 + 0).getAttribute('aria-setsize')
}
export function getNthStatus (n) {
@ -336,25 +336,25 @@ export async function validateTimeline (t, timeline) {
for (let i = 0; i < timeline.length; i++) {
let status = timeline[i]
// hovering forces TestCafé to scroll to that element: https://git.io/vABV2
await t.hover(getNthStatus(i))
await t.hover(getNthStatus(1 + i))
if (status.content) {
await t.expect(getNthStatusContent(i).innerText)
await t.expect(getNthStatusContent(1 + i).innerText)
.contains(status.content, { timeout })
}
if (status.spoiler) {
await t.expect(getNthStatusSpoiler(i).innerText)
await t.expect(getNthStatusSpoiler(1 + i).innerText)
.contains(status.spoiler, { timeout })
}
if (status.followedBy) {
await t.expect(getNthStatusHeader(i).innerText)
await t.expect(getNthStatusHeader(1 + i).innerText)
.match(new RegExp(status.followedBy + '\\s+followed you'), { timeout })
}
if (status.rebloggedBy) {
await t.expect(getNthStatusHeader(i).innerText)
await t.expect(getNthStatusHeader(1 + i).innerText)
.match(new RegExp(status.rebloggedBy + '\\s+boosted your status'), { timeout })
}
if (status.favoritedBy) {
await t.expect(getNthStatusHeader(i).innerText)
await t.expect(getNthStatusHeader(1 + i).innerText)
.match(new RegExp(status.favoritedBy + '\\s+favorited your status'), { timeout })
}
}
@ -362,14 +362,13 @@ export async function validateTimeline (t, timeline) {
export async function scrollToStatus (t, n) {
let timeout = 20000
for (let i = 0; i <= n; i++) {
for (let i = 1; i < n; i++) {
await t.expect(getNthStatus(i).exists).ok({ timeout })
.hover(getNthStatus(i))
.expect($('.loading-footer').exist).notOk()
if (i < n) {
await t.hover($(`${getNthStatusSelector(i)} .status-toolbar`))
.expect($('.loading-footer').exist).notOk()
}
.expect($('.loading-footer').exist).notOk({ timeout })
.expect($(`${getNthStatusSelector(i)} .status-toolbar`).exists).ok({ timeout })
.hover($(`${getNthStatusSelector(i)} .status-toolbar`))
.expect($('.loading-footer').exist).notOk({ timeout })
}
await t.hover(getNthStatus(n))
}