| @@ -16,11 +16,22 @@ const records = async (name, collection) => { |
| | return (await fetch(asked).then((r) => r.json())).records ?? [] |
| | } |
| | |
| | /// Until the page's script has taken it over, as the root says once |
| | /// mounted: a click before that reaches no handler. |
| | const ready = (page) => page.locator('html[data-ready]').waitFor({ state: 'attached' }) |
| | |
| | /// `page` at `path` of the pages, ready. |
| | const go = async (page, path) => { |
| | await page.goto(path.startsWith('http') ? path : url(path)) |
| | await ready(page) |
| | } |
| | |
| | /// Until `check` passes on `page` read anew: the index follows the PDS a |
| | /// moment behind. |
| | const anew = (page, check) => |
| | expect(async () => { |
| | await page.reload() |
| | await ready(page) |
| | await check() |
| | }).toPass({ timeout: 15_000 }) |
| | |
| @@ -38,6 +49,7 @@ const logIn = async (page, name, open = () => page.getByRole('button', { name: ' |
| | await page.getByRole('button', { name: 'Sign in' }).click() |
| | await page.getByRole('button', { name: /^(accept|authorize|allow)$/i }).click() |
| | await page.waitForURL(back) |
| | await ready(page) |
| | await expect(page.getByLabel('Your account')).toBeVisible() |
| | } |
| | |
| @@ -60,13 +72,13 @@ test.afterAll(async () => { |
| | }) |
| | |
| | test('logging in through the PDS', async () => { |
| | await page.goto(url('/alice.test/tally')) |
| | await go(page, '/alice.test/tally') |
| | await logIn(page, 'bob') |
| | await expect.poll(() => loggedInAs(page)).toBe('bob.test') |
| | }) |
| | |
| | test('starring and unstarring', async () => { |
| | await page.goto(url('/alice.test/notes')) |
| | await go(page, '/alice.test/notes') |
| | const star = page.getByRole('button', { name: 'Star', exact: true }) |
| | await star.click() |
| | const starred = page.getByRole('button', { name: 'Starred' }) |
| @@ -83,7 +95,7 @@ test('starring and unstarring', async () => { |
| | }) |
| | |
| | test('following and unfollowing', async () => { |
| | await page.goto(url('/textkit.test')) |
| | await go(page, '/textkit.test') |
| | await page.getByRole('button', { name: 'Follow', exact: true }).click() |
| | await expect(page.getByRole('button', { name: 'Unfollow' })).toHaveAttribute('aria-pressed', 'true') |
| | const follows = await records('bob', 'dev.knotless.follow') |
| @@ -97,7 +109,7 @@ test('following and unfollowing', async () => { |
| | let opened |
| | |
| | test('opening an issue', async () => { |
| | await page.goto(url('/alice.test/tally/issues/new')) |
| | await go(page, '/alice.test/tally/issues/new') |
| | await page.getByRole('textbox', { name: 'Title' }).fill('Counts a trailing newline as a line') |
| | await page.getByRole('textbox', { name: 'Description' }).fill('`printf "a\\n" | tally` says 1, as `wc` does. Is that meant?') |
| | await page.getByRole('button', { name: 'Open issue' }).click() |
| @@ -106,12 +118,12 @@ test('opening an issue', async () => { |
| | await expect(page.getByRole('heading', { name: 'Counts a trailing newline as a line' })).toBeVisible() |
| | const issues = await records('bob', 'dev.knotless.issue') |
| | expect(issues.map((r) => r.value.title)).toContain('Counts a trailing newline as a line') |
| | await page.goto(url('/alice.test/tally/issues')) |
| | await go(page, '/alice.test/tally/issues') |
| | await anew(page, () => expect(page.getByRole('link', { name: 'Counts a trailing newline as a line' })).toBeVisible()) |
| | }) |
| | |
| | test('commenting', async () => { |
| | await page.goto(opened) |
| | await go(page, opened) |
| | await page.getByPlaceholder('Leave a comment').fill('Ran it against `wc -l` on a few files: they agree.') |
| | await page.getByRole('button', { name: 'Comment', exact: true }).click() |
| | await expect(page.getByText('Ran it against wc -l on a few files: they agree.')).toBeVisible() |
| @@ -122,7 +134,7 @@ test('commenting', async () => { |
| | }) |
| | |
| | test('reacting', async () => { |
| | await page.goto(opened) |
| | await go(page, opened) |
| | const thread = page.locator('.reactions').first() |
| | await thread.locator('summary[aria-label="Add reaction"]').click() |
| | await thread.getByRole('button', { name: 'Eyes' }).click() |
| @@ -135,7 +147,7 @@ test('reacting', async () => { |
| | }) |
| | |
| | test('closing and reopening', async () => { |
| | await page.goto(opened) |
| | await go(page, opened) |
| | await page.getByRole('button', { name: 'Close issue' }).click() |
| | await expect(page.getByRole('button', { name: 'Reopen issue' })).toBeVisible() |
| | await anew(page, () => expect(page.getByRole('button', { name: 'Reopen issue' })).toBeVisible()) |
| @@ -144,8 +156,49 @@ test('closing and reopening', async () => { |
| | await anew(page, () => expect(page.getByRole('button', { name: 'Close issue' })).toBeVisible()) |
| | }) |
| | |
| | test('forking', async () => { |
| | await go(page, '/alice.test/notes') |
| | await page.locator('.fork-menu summary').click() |
| | await expect(page.getByLabel('Name')).toHaveValue('notes') |
| | await page.getByRole('button', { name: 'Create fork' }).click() |
| | await page.waitForURL(url('/bob.test/notes')) |
| | await expect(page.getByText('Forked from')).toBeVisible() |
| | expect((await records('bob', 'dev.knotless.repo')).map((r) => r.uri.split('/').pop())).toContain('notes') |
| | // Every branch came with it. |
| | await go(page, '/bob.test/notes/branches') |
| | await anew(page, () => expect(page.getByRole('link', { name: 'reading', exact: true })).toBeVisible()) |
| | }) |
| | |
| | test('merging a pull', async () => { |
| | // The fork's pull its queue ejected: merged by hand, by bob, its owner. |
| | await go(page, world.views['pull-ejected']) |
| | const box = page.locator('.merge-box') |
| | await box.getByRole('button', { name: 'Merge pull' }).click() |
| | // The page asks its answers again once merged, and the thread says so, |
| | // with a way to revert it, in place of the box: the box's own word for |
| | // it shows only until then, which can be no time at all. |
| | const said = page.locator('.event', { hasText: 'Merged as' }) |
| | await expect(said.getByText(/^[0-9a-f]{7}$/)).toBeVisible() |
| | const sha = await said.getByText(/^[0-9a-f]{7}$/).innerText() |
| | await expect(page.getByRole('button', { name: 'Revert' })).toBeVisible() |
| | await anew(page, () => expect(page.locator('.event', { hasText: 'Merged as' }).getByText(sha)).toBeVisible()) |
| | await go(page, '/bob.test/tally/commits/main') |
| | await anew(page, () => expect(page.getByText('Print a total for many files').first()).toBeVisible()) |
| | }) |
| | |
| | test('leaving the merge queue and joining it again', async () => { |
| | await go(page, world.views['pull-queued']) |
| | const box = page.locator('.merge-box') |
| | await box.getByRole('button', { name: 'Leave queue' }).click() |
| | await expect(box.getByRole('button', { name: 'Add to merge queue' })).toBeVisible() |
| | await anew(page, () => expect(page.locator('.merge-box').getByRole('button', { name: 'Add to merge queue' })).toBeVisible()) |
| | await page.locator('.merge-box').getByRole('button', { name: 'Add to merge queue' }).click() |
| | await expect(page.locator('.merge-box').getByRole('button', { name: 'Leave queue' })).toBeVisible() |
| | await anew(page, () => expect(page.locator('.merge-box').getByRole('button', { name: 'Leave queue' })).toBeVisible()) |
| | }) |
| | |
| | test('logging in to a second account and labelling as the owner', async () => { |
| | await page.goto(opened) |
| | await go(page, opened) |
| | // bob, not the owner, has no labels to apply. |
| | await expect(page.locator('.label-menu')).toHaveCount(0) |
| | await logIn(page, 'alice', async () => { |
| @@ -160,7 +213,7 @@ test('logging in to a second account and labelling as the owner', async () => { |
| | }) |
| | |
| | test('switching back and logging out', async () => { |
| | await page.goto(opened) |
| | await go(page, opened) |
| | await page.getByLabel('Your account').click() |
| | await page.locator('.account .menu-item.switch', { hasText: 'bob.test' }).click() |
| | await expect.poll(() => loggedInAs(page)).toBe('bob.test') |
| @@ -173,7 +226,8 @@ test('switching back and logging out', async () => { |
| | await page.getByRole('button', { name: 'Log out' }).click() |
| | await expect(page.getByRole('button', { name: 'Log in' })).toBeVisible() |
| | // Starring asks who is starring first. |
| | await page.goto(url('/alice.test/notes')) |
| | await go(page, '/alice.test/notes') |
| | await page.getByRole('button', { name: 'Star', exact: true }).click() |
| | await expect(page.getByRole('dialog', { name: 'Log in with your Atmosphere account' })).toBeVisible() |
| | }) |
| | |
| |