diff --git a/README.md b/README.md index 8770fcfc4b..0cbfe77377 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Get the app itself: - **Web: [bsky.app](https://bsky.app)** - **iOS: [App Store](https://apps.apple.com/us/app/bluesky-social/id6444370199)** -- **Android: [Play Store](https://play.google.com/store/apps/details?id=xyz.blueskyweb.app&hl=en_US&gl=US)** +- **Android: [Play Store](https://play.google.com/store/apps/details?id=xyz.blueskyweb.app)** ## Development Resources @@ -21,7 +21,7 @@ The Authenticated Transfer Protocol ("AT Protocol" or "atproto") is a decentrali - [Overview and Guides](https://atproto.com/guides/overview) - [Github Discussions](https://github.com/bluesky-social/atproto/discussions) 👈 Great place to ask questions - [Protocol Specifications](https://atproto.com/specs/atp) -- [Blogpost on self-authenticating data structures](https://blueskyweb.xyz/blog/3-6-2022-a-self-authenticating-social-protocol) +- [Blogpost on self-authenticating data structures](https://bsky.social/about/blog/3-6-2022-a-self-authenticating-social-protocol) The Bluesky Social application encompasses a set of schemas and APIs built in the overall AT Protocol framework. The namespace for these "Lexicons" is `app.bsky.*`. diff --git a/__e2e__/tests/create-account.test.ts b/__e2e__/tests/create-account.test.ts index a6724e8e45..9c56c914ea 100644 --- a/__e2e__/tests/create-account.test.ts +++ b/__e2e__/tests/create-account.test.ts @@ -18,9 +18,10 @@ describe('Create account', () => { await device.takeScreenshot('1- opened create account screen') await element(by.id('selectServiceButton')).tap() await device.takeScreenshot('2- selected other server') + await element(by.id('customSelectBtn')).tap() await element(by.id('customServerTextInput')).typeText(service) await element(by.id('customServerTextInput')).tapReturnKey() - await element(by.id('customServerSelectBtn')).tap() + await element(by.id('doneBtn')).tap() await device.takeScreenshot('3- input test server URL') await element(by.id('emailInput')).typeText('example@test.com') await element(by.id('passwordInput')).typeText('hunter2') @@ -33,12 +34,6 @@ describe('Create account', () => { await element(by.id('nextBtn')).tap() - await expect(element(by.id('welcomeOnboarding'))).toBeVisible() - await element(by.id('continueBtn')).tap() - await expect(element(by.id('recommendedFeedsOnboarding'))).toBeVisible() - await element(by.id('continueBtn')).tap() - await expect(element(by.id('recommendedFollowsOnboarding'))).toBeVisible() - await element(by.id('continueBtn')).tap() - await expect(element(by.id('homeScreen'))).toBeVisible() + await expect(element(by.id('onboardingInterests'))).toBeVisible() }) }) diff --git a/__e2e__/tests/home-screen.test.ts b/__e2e__/tests/home-screen.test.ts index 79fca1e6a5..ce7f1643bd 100644 --- a/__e2e__/tests/home-screen.test.ts +++ b/__e2e__/tests/home-screen.test.ts @@ -36,7 +36,7 @@ describe('Home screen', () => { const carlaPosts = by.id('feedItem-by-carla.test') await expect( element(by.id('likeCount').withAncestor(carlaPosts)).atIndex(0), - ).toHaveText('0') + ).not.toExist() await element(by.id('likeBtn').withAncestor(carlaPosts)).atIndex(0).tap() await expect( element(by.id('likeCount').withAncestor(carlaPosts)).atIndex(0), @@ -44,14 +44,14 @@ describe('Home screen', () => { await element(by.id('likeBtn').withAncestor(carlaPosts)).atIndex(0).tap() await expect( element(by.id('likeCount').withAncestor(carlaPosts)).atIndex(0), - ).toHaveText('0') + ).not.toExist() }) it('Can repost posts', async () => { const carlaPosts = by.id('feedItem-by-carla.test') await expect( element(by.id('repostCount').withAncestor(carlaPosts)).atIndex(0), - ).toHaveText('0') + ).not.toExist() await element(by.id('repostBtn').withAncestor(carlaPosts)).atIndex(0).tap() await expect(element(by.id('repostModal'))).toBeVisible() await element(by.id('repostBtn').withAncestor(by.id('repostModal'))).tap() @@ -65,7 +65,7 @@ describe('Home screen', () => { await expect(element(by.id('repostModal'))).not.toBeVisible() await expect( element(by.id('repostCount').withAncestor(carlaPosts)).atIndex(0), - ).toHaveText('0') + ).not.toExist() }) it('Can report posts', async () => { diff --git a/__e2e__/tests/invite-codes.test.ts b/__e2e__/tests/invite-codes.test.ts index 7ab5b1477b..7eb8d9a3e1 100644 --- a/__e2e__/tests/invite-codes.test.ts +++ b/__e2e__/tests/invite-codes.test.ts @@ -28,9 +28,10 @@ describe('invite-codes', () => { await device.takeScreenshot('1- opened create account screen') await element(by.id('selectServiceButton')).tap() await device.takeScreenshot('2- selected other server') + await element(by.id('customSelectBtn')).tap() await element(by.id('customServerTextInput')).typeText(service) await element(by.id('customServerTextInput')).tapReturnKey() - await element(by.id('customServerSelectBtn')).tap() + await element(by.id('doneBtn')).tap() await device.takeScreenshot('3- input test server URL') await element(by.id('inviteCodeInput')).typeText(inviteCode) await element(by.id('emailInput')).typeText('example@test.com') @@ -40,12 +41,6 @@ describe('invite-codes', () => { await element(by.id('handleInput')).typeText('e2e-test') await device.takeScreenshot('4- entered handle') await element(by.id('nextBtn')).tap() - await expect(element(by.id('welcomeOnboarding'))).toBeVisible() - await element(by.id('continueBtn')).tap() - await expect(element(by.id('recommendedFeedsOnboarding'))).toBeVisible() - await element(by.id('continueBtn')).tap() - await expect(element(by.id('recommendedFollowsOnboarding'))).toBeVisible() - await element(by.id('continueBtn')).tap() - await expect(element(by.id('homeScreen'))).toBeVisible() + await expect(element(by.id('onboardingInterests'))).toBeVisible() }) }) diff --git a/__e2e__/tests/invites-and-text-verification.test.ts b/__e2e__/tests/invites-and-text-verification.test.ts index 850ca6d5c7..863b31107b 100644 --- a/__e2e__/tests/invites-and-text-verification.test.ts +++ b/__e2e__/tests/invites-and-text-verification.test.ts @@ -28,16 +28,17 @@ describe('invite-codes', () => { await device.takeScreenshot('1- opened create account screen') await element(by.id('selectServiceButton')).tap() await device.takeScreenshot('2- selected other server') + await element(by.id('customSelectBtn')).tap() await element(by.id('customServerTextInput')).typeText(service) await element(by.id('customServerTextInput')).tapReturnKey() - await element(by.id('customServerSelectBtn')).tap() + await element(by.id('doneBtn')).tap() await device.takeScreenshot('3- input test server URL') await element(by.id('inviteCodeInput')).typeText(inviteCode) await element(by.id('emailInput')).typeText('example@test.com') await element(by.id('passwordInput')).typeText('hunter2') await device.takeScreenshot('4- entered account details') await element(by.id('nextBtn')).tap() - await element(by.id('phoneInput')).typeText('5558675309') + await element(by.id('phoneInput')).typeText('2345551234') await element(by.id('requestCodeBtn')).tap() await device.takeScreenshot('5- requested code') await element(by.id('codeInput')).typeText('000000') @@ -46,12 +47,6 @@ describe('invite-codes', () => { await element(by.id('handleInput')).typeText('e2e-test') await device.takeScreenshot('7- entered handle') await element(by.id('nextBtn')).tap() - await expect(element(by.id('welcomeOnboarding'))).toBeVisible() - await element(by.id('continueBtn')).tap() - await expect(element(by.id('recommendedFeedsOnboarding'))).toBeVisible() - await element(by.id('continueBtn')).tap() - await expect(element(by.id('recommendedFollowsOnboarding'))).toBeVisible() - await element(by.id('continueBtn')).tap() - await expect(element(by.id('homeScreen'))).toBeVisible() + await expect(element(by.id('onboardingInterests'))).toBeVisible() }) }) diff --git a/__e2e__/tests/mod-lists.test.ts b/__e2e__/tests/mod-lists.test.ts index 5280920b4b..c3d4149e09 100644 --- a/__e2e__/tests/mod-lists.test.ts +++ b/__e2e__/tests/mod-lists.test.ts @@ -2,7 +2,7 @@ import {describe, beforeAll, it} from '@jest/globals' import {expect} from 'detox' -import {openApp, loginAsAlice, loginAsBob, createServer, sleep} from '../util' +import {openApp, loginAsAlice, loginAsBob, createServer} from '../util' describe('Mod lists', () => { beforeAll(async () => { @@ -62,38 +62,39 @@ describe('Mod lists', () => { .withTimeout(5000) }) - it('Set avi via the edit modlist modal', async () => { - await expect(element(by.id('userAvatarFallback'))).toExist() - await element(by.id('headerDropdownBtn')).tap() - await element(by.text('Edit list details')).tap() - await expect(element(by.id('createOrEditListModal'))).toBeVisible() - await element(by.id('changeAvatarBtn')).tap() - await element(by.text('Library')).tap() - await sleep(3e3) - await element(by.id('saveBtn')).tap() - await expect(element(by.id('createOrEditListModal'))).not.toBeVisible() - await expect(element(by.id('userAvatarImage'))).toExist() - // have to wait for the toast to clear - await waitFor(element(by.id('headerDropdownBtn'))) - .toBeVisible() - .withTimeout(5000) - }) + // DISABLED e2e environment is real finicky about avatar uploads -prf + // it('Set avi via the edit modlist modal', async () => { + // await expect(element(by.id('userAvatarFallback'))).toExist() + // await element(by.id('headerDropdownBtn')).tap() + // await element(by.text('Edit list details')).tap() + // await expect(element(by.id('createOrEditListModal'))).toBeVisible() + // await element(by.id('changeAvatarBtn')).tap() + // await element(by.text('Library')).tap() + // await sleep(3e3) + // await element(by.id('saveBtn')).tap() + // await expect(element(by.id('createOrEditListModal'))).not.toBeVisible() + // await expect(element(by.id('userAvatarImage'))).toExist() + // // have to wait for the toast to clear + // await waitFor(element(by.id('headerDropdownBtn'))) + // .toBeVisible() + // .withTimeout(5000) + // }) - it('Remove avi via the edit modlist modal', async () => { - await expect(element(by.id('userAvatarImage'))).toExist() - await element(by.id('headerDropdownBtn')).tap() - await element(by.text('Edit list details')).tap() - await expect(element(by.id('createOrEditListModal'))).toBeVisible() - await element(by.id('changeAvatarBtn')).tap() - await element(by.text('Remove')).tap() - await element(by.id('saveBtn')).tap() - await expect(element(by.id('createOrEditListModal'))).not.toBeVisible() - await expect(element(by.id('userAvatarFallback'))).toExist() - // have to wait for the toast to clear - await waitFor(element(by.id('headerDropdownBtn'))) - .toBeVisible() - .withTimeout(5000) - }) + // it('Remove avi via the edit modlist modal', async () => { + // await expect(element(by.id('userAvatarImage'))).toExist() + // await element(by.id('headerDropdownBtn')).tap() + // await element(by.text('Edit list details')).tap() + // await expect(element(by.id('createOrEditListModal'))).toBeVisible() + // await element(by.id('changeAvatarBtn')).tap() + // await element(by.text('Remove')).tap() + // await element(by.id('saveBtn')).tap() + // await expect(element(by.id('createOrEditListModal'))).not.toBeVisible() + // await expect(element(by.id('userAvatarFallback'))).toExist() + // // have to wait for the toast to clear + // await waitFor(element(by.id('headerDropdownBtn'))) + // .toBeVisible() + // .withTimeout(5000) + // }) it('Delete the modlist', async () => { await element(by.id('headerDropdownBtn')).tap() diff --git a/__e2e__/tests/profile-screen.test.ts b/__e2e__/tests/profile-screen.test.ts index b4624e4567..7ff43642f9 100644 --- a/__e2e__/tests/profile-screen.test.ts +++ b/__e2e__/tests/profile-screen.test.ts @@ -147,7 +147,7 @@ describe('Profile screen', () => { const posts = by.id('feedItem-by-bob.test') await expect( element(by.id('likeCount').withAncestor(posts)).atIndex(0), - ).toHaveText('0') + ).not.toExist() await element(by.id('likeBtn').withAncestor(posts)).atIndex(0).tap() await expect( element(by.id('likeCount').withAncestor(posts)).atIndex(0), @@ -155,14 +155,14 @@ describe('Profile screen', () => { await element(by.id('likeBtn').withAncestor(posts)).atIndex(0).tap() await expect( element(by.id('likeCount').withAncestor(posts)).atIndex(0), - ).toHaveText('0') + ).not.toExist() }) it('Can repost posts', async () => { const posts = by.id('feedItem-by-bob.test') await expect( element(by.id('repostCount').withAncestor(posts)).atIndex(0), - ).toHaveText('0') + ).not.toExist() await element(by.id('repostBtn').withAncestor(posts)).atIndex(0).tap() await expect(element(by.id('repostModal'))).toBeVisible() await element(by.id('repostBtn').withAncestor(by.id('repostModal'))).tap() @@ -176,7 +176,7 @@ describe('Profile screen', () => { await expect(element(by.id('repostModal'))).not.toBeVisible() await expect( element(by.id('repostCount').withAncestor(posts)).atIndex(0), - ).toHaveText('0') + ).not.toExist() }) it('Can report posts', async () => { diff --git a/__e2e__/tests/self-labeling.test.ts b/__e2e__/tests/self-labeling.test.ts index f629f91a8d..bba8ed484c 100644 --- a/__e2e__/tests/self-labeling.test.ts +++ b/__e2e__/tests/self-labeling.test.ts @@ -28,6 +28,7 @@ describe('Self-labeling', () => { await element(by.id('composerPublishBtn')).tap() await expect(element(by.id('composeFAB'))).toBeVisible() const posts = by.id('feedItem-by-alice.test') + await element(by.id('e2eRefreshHome')).tap() await expect( element(by.id('contentHider-embed').withAncestor(posts)).atIndex(0), ).toExist() diff --git a/__e2e__/tests/text-verification.test.ts b/__e2e__/tests/text-verification.test.ts index 3c556c2390..79b14aecaa 100644 --- a/__e2e__/tests/text-verification.test.ts +++ b/__e2e__/tests/text-verification.test.ts @@ -18,9 +18,10 @@ describe('Create account', () => { await device.takeScreenshot('1- opened create account screen') await element(by.id('selectServiceButton')).tap() await device.takeScreenshot('2- selected other server') + await element(by.id('customSelectBtn')).tap() await element(by.id('customServerTextInput')).typeText(service) await element(by.id('customServerTextInput')).tapReturnKey() - await element(by.id('customServerSelectBtn')).tap() + await element(by.id('doneBtn')).tap() await device.takeScreenshot('3- input test server URL') await element(by.id('emailInput')).typeText('text-verification@test.com') await element(by.id('passwordInput')).typeText('hunter2') @@ -40,13 +41,7 @@ describe('Create account', () => { await element(by.id('nextBtn')).tap() - await expect(element(by.id('welcomeOnboarding'))).toBeVisible() - await element(by.id('continueBtn')).tap() - await expect(element(by.id('recommendedFeedsOnboarding'))).toBeVisible() - await element(by.id('continueBtn')).tap() - await expect(element(by.id('recommendedFollowsOnboarding'))).toBeVisible() - await element(by.id('continueBtn')).tap() - await expect(element(by.id('homeScreen'))).toBeVisible() + await expect(element(by.id('onboardingInterests'))).toBeVisible() }) it('failed text verification correctly goes back to the code input screen', async () => { @@ -57,9 +52,10 @@ describe('Create account', () => { await device.takeScreenshot('1- opened create account screen') await element(by.id('selectServiceButton')).tap() await device.takeScreenshot('2- selected other server') + await element(by.id('customSelectBtn')).tap() await element(by.id('customServerTextInput')).typeText(service) await element(by.id('customServerTextInput')).tapReturnKey() - await element(by.id('customServerSelectBtn')).tap() + await element(by.id('doneBtn')).tap() await device.takeScreenshot('3- input test server URL') await element(by.id('emailInput')).typeText('text-verification2@test.com') await element(by.id('passwordInput')).typeText('hunter2') diff --git a/__e2e__/tests/thread-screen.test.ts b/__e2e__/tests/thread-screen.test.ts index e3cff12c9f..646c828fd3 100644 --- a/__e2e__/tests/thread-screen.test.ts +++ b/__e2e__/tests/thread-screen.test.ts @@ -49,7 +49,7 @@ describe('Thread screen', () => { const post = by.id('postThreadItem-by-carla.test') await expect( element(by.id('likeCount').withAncestor(post)).atIndex(0), - ).toHaveText('0') + ).not.toExist() await element(by.id('likeBtn').withAncestor(post)).atIndex(0).tap() await expect( element(by.id('likeCount').withAncestor(post)).atIndex(0), @@ -57,7 +57,7 @@ describe('Thread screen', () => { await element(by.id('likeBtn').withAncestor(post)).atIndex(0).tap() await expect( element(by.id('likeCount').withAncestor(post)).atIndex(0), - ).toHaveText('0') + ).not.toExist() }) it('Can repost the root post', async () => { @@ -85,7 +85,7 @@ describe('Thread screen', () => { const post = by.id('postThreadItem-by-carla.test') await expect( element(by.id('repostCount').withAncestor(post)).atIndex(0), - ).toHaveText('0') + ).not.toExist() await element(by.id('repostBtn').withAncestor(post)).atIndex(0).tap() await expect(element(by.id('repostModal'))).toBeVisible() await element(by.id('repostBtn').withAncestor(by.id('repostModal'))).tap() @@ -99,7 +99,7 @@ describe('Thread screen', () => { await expect(element(by.id('repostModal'))).not.toBeVisible() await expect( element(by.id('repostCount').withAncestor(post)).atIndex(0), - ).toHaveText('0') + ).not.toExist() }) it('Can report the root post', async () => { diff --git a/__e2e__/util.ts b/__e2e__/util.ts index 8c47406c07..a7869a2e1d 100644 --- a/__e2e__/util.ts +++ b/__e2e__/util.ts @@ -56,9 +56,10 @@ export async function login( if (takeScreenshots) { await device.takeScreenshot('2- opened service selector') } + await element(by.id('customSelectBtn')).tap() await element(by.id('customServerTextInput')).typeText(service) await element(by.id('customServerTextInput')).tapReturnKey() - await element(by.id('customServerSelectBtn')).tap() + await element(by.id('doneBtn')).tap() if (takeScreenshots) { await device.takeScreenshot('3- input custom service') } diff --git a/bskyweb/templates/base.html b/bskyweb/templates/base.html index b7913c3ade..a2d81fc96a 100644 --- a/bskyweb/templates/base.html +++ b/bskyweb/templates/base.html @@ -4,6 +4,11 @@ + + + {%- block head_title -%}Bluesky{%- endblock -%} @@ -219,7 +224,7 @@