start migrating to testcafe

This commit is contained in:
Nolan Lawson 2018-02-19 17:04:37 -08:00
parent b0a8ce1efb
commit 13a2195035
7 changed files with 1859 additions and 0 deletions

1624
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -60,6 +60,7 @@
"svelte-loader": "^2.3.3",
"svelte-transitions": "^1.1.1",
"svgo": "^1.0.3",
"testcafe": "^0.19.0-alpha1",
"timeago.js": "^3.0.2",
"tiny-queue": "^0.2.1",
"uglifyjs-webpack-plugin": "^1.1.5",

54
tests/fixtures.js Normal file
View File

@ -0,0 +1,54 @@
import times from 'lodash/times'
export const homeTimeline = [
{content: 'pinned toot 1'},
{content: 'notification of unlisted message'},
{content: 'notification of followers-only message'},
{content: 'notification of direct message'},
{content: 'this is unlisted'},
{content: 'this is followers-only'},
{content: 'direct'},
{spoiler: 'kitten CW'},
{content: 'secret video'},
{content: "here's a video"},
{spoiler: 'CW'},
{content: "here's a secret animated kitten gif"},
{content: "here's an animated kitten gif"},
{content: "here's 2 kitten photos"},
{content: "here's a secret kitten"},
{content: "here's a kitten"},
{content: 'hello admin'},
{content: 'hello foobar'},
{content: 'hello world'}
].concat(times(30, i => ({content: (30 - i).toString()})))
export const localTimeline = [
{spoiler: 'kitten CW'},
{content: 'secret video'},
{content: "here's a video"},
{spoiler: 'CW'},
{content: "here's a secret animated kitten gif"},
{content: "here's an animated kitten gif"},
{content: "here's 2 kitten photos"},
{content: "here's a secret kitten"},
{content: "here's a kitten"},
{content: 'hello world'}
].concat(times(30, i => ({content: (30 - i).toString()})))
export const notifications = [
{favoritedBy: 'admin'},
{rebloggedBy: 'admin'},
{content: 'notification of unlisted message'},
{content: 'notification of followers-only message'},
{content: 'notification of direct message'},
{followedBy: 'quux'},
{content: 'hello foobar'},
{followedBy: 'admin'}
]
export const favorites = [
{content: 'notification of direct message'},
{content: 'notification of followers-only message'},
{content: 'notification of unlisted message'},
{content: 'pinned toot 1'}
]

View File

@ -0,0 +1,33 @@
import { Selector as $ } from 'testcafe'
import { getUrl, settingsButton } from '../utils'
fixture `01-basic-spec.js`
.page `http://localhost:4002`
test('has the correct <h1>', async t => {
await t
.expect($('.container h1').innerText).eql('Pinafore')
})
test('navigates to about', async t => {
await t
.click(settingsButton)
.expect(getUrl()).contains('/settings')
.click('a[href="/settings/about"]')
.expect(getUrl()).contains('/about')
.expect($('.container h1').innerText).eql('About Pinafore')
})
test('navigates to /settings/instances/add', async t => {
await t.click($('a').withText('log in to an instance'))
.expect(getUrl()).contains('/settings/instances/add')
})
test('navigates to settings/instances', async t => {
await t.click(settingsButton)
.expect(getUrl()).contains('/settings')
.click($('a').withText('Instances'))
.expect(getUrl()).contains('/settings/instances')
.expect($('.container').innerText)
.contains("You're not logged in to any instances")
})

View File

@ -0,0 +1,37 @@
import { Selector as $ } from 'testcafe'
import { addInstanceButton, getUrl, instanceInput, login, settingsButton } from '../utils'
fixture `02-login-spec.js`
.page `http://localhost:4002`
const formError = $('.form-error')
test('Cannot log in to a fake instance', async t => {
await t.click($('a').withText('log in to an instance'))
.typeText(instanceInput, 'fake.nolanlawson.com')
.click(addInstanceButton)
.expect(formError.exists).ok()
.expect(formError.innerText).contains('Is this a valid Mastodon instance?')
.typeText(instanceInput, '.biz')
.expect(formError.exists).notOk()
.typeText(instanceInput, 'fake.nolanlawson.com', {replace: true})
.expect(formError.exists).ok()
.expect(formError.innerText).contains('Is this a valid Mastodon instance?')
})
test('Logs in to localhost:3000', async t => {
await login(t, 'foobar@localhost:3000', 'foobarfoobar')
.expect($('article.status-article').exists).ok()
})
test('Logs out', async t => {
await login(t, 'foobar@localhost:3000', 'foobarfoobar')
.click(settingsButton)
.click($('a').withText('Instances'))
.click($('a').withText('localhost:3000'))
.expect(getUrl()).contains('/settings/instances/localhost:3000')
.click($('button').withText('Log out'))
.click($('#modal-dialog button').withText('OK'))
.expect($('.container').innerText)
.contains("You're not logged in to any instances")
})

View File

@ -0,0 +1,53 @@
import { Selector as $ } from 'testcafe'
import { getUrl, login, validateTimeline } from '../utils'
import { homeTimeline, notifications, localTimeline, favorites } from '../fixtures'
fixture `03-basic-timeline-spec.js`
.page `http://localhost:4002`
.beforeEach(async t => {
await login(t, 'foobar@localhost:3000', 'foobarfoobar')
})
const firstArticle = $('.virtual-list-item[aria-hidden=false] .status-article')
test('Shows the home timeline', async t => {
await t
.expect(firstArticle.hasAttribute('aria-setsize')).ok()
.expect(firstArticle.getAttribute('aria-posinset')).eql('0')
await validateTimeline(t, homeTimeline)
await t.expect(firstArticle.getAttribute('aria-setsize')).eql('49')
})
test('Shows notifications', async t => {
await t.click($('nav a[aria-label=Notifications]'))
.expect(getUrl()).contains('/notifications')
await validateTimeline(t, notifications)
})
test('Shows the local timeline', async t => {
await t.click($('nav a[aria-label=Local]'))
await t.expect(getUrl()).contains('/local')
await validateTimeline(t, localTimeline)
})
test('Shows the federated timeline', async t => {
await t.click($('nav a[aria-label=Community]'))
.expect(getUrl()).contains('/community')
.click($('a').withText('Federated'))
.expect(getUrl()).contains('/federated')
await validateTimeline(t, localTimeline) // local is same as federated in this case
})
test('Shows favorites', async t => {
await t.click($('nav a[aria-label=Community]'))
.expect(getUrl()).contains('/community')
.click($('a').withText('Favorites'))
.expect(getUrl()).contains('/favorites')
await validateTimeline(t, favorites)
})

57
tests/utils.js Normal file
View File

@ -0,0 +1,57 @@
import { ClientFunction as exec, Selector as $ } from 'testcafe'
export const settingsButton = $('nav a[aria-label=Settings]')
export const instanceInput = $('#instanceInput')
export const addInstanceButton = $('.add-new-instance button')
export const getUrl = exec(() => window.location.href)
export function login(t, username, password) {
return t.click($('a').withText('log in to an instance'))
.expect(getUrl()).contains('/settings/instances/add')
.typeText(instanceInput, 'localhost:3000')
.click(addInstanceButton)
.expect(getUrl()).eql('http://localhost:3000/auth/sign_in')
.typeText($('input#user_email'), username)
.typeText($('input#user_password'), password)
.click($('button[type=submit]'))
.expect(getUrl()).contains('/oauth/authorize')
.click($('button[type=submit]:not(.negative)'))
.expect(getUrl()).eql('http://localhost:4002/')
}
export function getNthVirtualArticle (n) {
return $(`.virtual-list-item[aria-hidden="false"] article[aria-posinset="${n}"]`)
}
export async function validateTimeline(t, timeline) {
for (let i = 0; i < timeline.length; i++) {
let status = timeline[i]
if (status.content) {
await t.expect(getNthVirtualArticle(i).find('.status-content p').innerText)
.contains(status.content)
}
if (status.spoiler) {
await t.expect(getNthVirtualArticle(i).find('.status-spoiler p').innerText)
.contains(status.spoiler)
}
if (status.followedBy) {
await t.expect(getNthVirtualArticle(i).find('.status-header span').innerText)
.contains(status.followedBy + ' followed you')
}
if (status.rebloggedBy) {
await t.expect(getNthVirtualArticle(i).find('.status-header span').innerText)
.contains(status.rebloggedBy + ' boosted your status')
}
if (status.favoritedBy) {
await t.expect(getNthVirtualArticle(i).find('.status-header span').innerText)
.contains(status.favoritedBy + ' favorited your status')
}
// hovering forces TestCafé to scroll to that element: https://git.io/vABV2
if (i % 3 === 2) { // only scroll every nth element
await t.hover(getNthVirtualArticle(i))
await t.expect($('.loading-footer').exist).notOk()
}
}
}