Some checks failed
Deploy analytics worker / Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
i18n upload strings / Upload latest strings (push) Failing after 1s
Deploy bemo / Deploy bemo to ${{ (github.ref == 'refs/heads/bemo-production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
Deploy grafana resources / ${{ github.event_name == 'push' && 'Deploy grafana resources' || 'Validate grafana resources (dry run)' }} (push) Failing after 0s
End to end tests (dotcom) / Check for relevant changes (push) Failing after 0s
End to end tests (examples) / Check for relevant changes (push) Failing after 0s
End to end tests (mermaid readability) / Check for relevant changes (push) Failing after 1s
End to end tests (perf) / Check for relevant changes (push) Failing after 0s
Publish editor extensions / Publish editor extensions (push) Failing after 1s
Publish SDK packages / Remove the publish-packages label (push) Has been skipped
Checks / Tests & checks (push) Has been cancelled
Checks / Build all projects (push) Has been cancelled
Deploy templates / Deploy templates (push) Has been cancelled
End to end tests (dotcom) / End to end tests (dotcom) (push) Has been cancelled
End to end tests (mermaid readability) / End to end tests (mermaid readability) (push) Has been cancelled
End to end tests (perf) / End to end tests (perf) (push) Has been cancelled
Deploy .com / Deploy dotcom to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Has been cancelled
End to end tests (examples) / End to end tests (examples) (push) Has been cancelled
Publish SDK packages / Publish SDK packages (push) Has been cancelled
Publish SDK packages / Tell user released version (push) Has been cancelled
Publish SDK packages / Publishes code templates to separate repositories (push) Has been cancelled
Publish SDK packages / Deploys the template demos with the new SDK version (push) Has been cancelled
384 lines
14 KiB
TypeScript
384 lines
14 KiB
TypeScript
import fs from 'fs'
|
|
import path from 'path'
|
|
import { getRandomName, openNewTab } from '../../fixtures/helpers'
|
|
import { expect, test } from '../../fixtures/tla-test'
|
|
|
|
test.beforeEach(async ({ context }) => {
|
|
await context.grantPermissions(['clipboard-read', 'clipboard-write'])
|
|
})
|
|
|
|
/* --------------------- Sharing -------------------- */
|
|
|
|
test.describe('signed in user on own file', () => {
|
|
test('default share state', async ({ shareMenu }) => {
|
|
await shareMenu.open()
|
|
expect(await shareMenu.isToggleChecked()).toBe(true)
|
|
expect(await shareMenu.getShareType()).toBe('Editor')
|
|
})
|
|
|
|
test('tabs work correctly', async ({ shareMenu }) => {
|
|
await shareMenu.open()
|
|
expect(await shareMenu.publishTabButton.isVisible()).toBe(true)
|
|
expect(await shareMenu.inviteTabButton.isVisible()).toBe(true)
|
|
expect(await shareMenu.exportTabButton.isVisible()).toBe(true)
|
|
expect(await shareMenu.anonShareTabButton.isVisible()).toBe(false)
|
|
|
|
// Starts on the invite tab
|
|
expect(await shareMenu.inviteTabPage.isVisible()).toBe(true)
|
|
expect(await shareMenu.exportTabPage.isVisible()).toBe(false)
|
|
expect(await shareMenu.publishTabPage.isVisible()).toBe(false)
|
|
expect(await shareMenu.anonShareTabPage.isVisible()).toBe(false)
|
|
|
|
// Can switch between tabs (export)
|
|
await shareMenu.exportTabButton.click()
|
|
expect(await shareMenu.inviteTabPage.isVisible()).toBe(false)
|
|
expect(await shareMenu.exportTabPage.isVisible()).toBe(true)
|
|
expect(await shareMenu.publishTabPage.isVisible()).toBe(false)
|
|
|
|
// Can switch between tabs (publish)
|
|
await shareMenu.publishTabButton.click()
|
|
expect(await shareMenu.inviteTabPage.isVisible()).toBe(false)
|
|
expect(await shareMenu.exportTabPage.isVisible()).toBe(false)
|
|
expect(await shareMenu.publishTabPage.isVisible()).toBe(true)
|
|
})
|
|
|
|
test('a select inside the menu closes without closing the menu', async ({ page, shareMenu }) => {
|
|
await shareMenu.open()
|
|
await shareMenu.exportTabButton.click()
|
|
await expect(shareMenu.exportTabPage).toBeVisible()
|
|
|
|
const themeSelect = page.locator('#tla-export-theme-select')
|
|
|
|
// Selecting an option closes the select but leaves the share menu open.
|
|
await themeSelect.click()
|
|
await expect(page.getByRole('listbox')).toBeVisible()
|
|
await page.getByRole('option').last().click()
|
|
await expect(page.getByRole('listbox')).toHaveCount(0)
|
|
await expect(shareMenu.exportTabPage).toBeVisible()
|
|
|
|
// Re-clicking the open select's trigger also closes only the select. The trigger
|
|
// is non-interactive while the select is open (Radix disables outside pointer
|
|
// events), so click its position directly rather than via the locator.
|
|
await themeSelect.click()
|
|
await expect(page.getByRole('listbox')).toBeVisible()
|
|
const box = await themeSelect.boundingBox()
|
|
if (!box) throw new Error('theme select not found')
|
|
await page.mouse.click(box.x + box.width / 2, box.y + box.height / 2)
|
|
await expect(page.getByRole('listbox')).toHaveCount(0)
|
|
await expect(shareMenu.exportTabPage).toBeVisible()
|
|
})
|
|
|
|
test('can unshare and reshare', async ({ page, browser, shareMenu }) => {
|
|
// Copy the link to the current file
|
|
await shareMenu.open()
|
|
expect(await shareMenu.isInviteButtonVisible()).toBe(true)
|
|
const url = await shareMenu.copyLink()
|
|
|
|
// Open link in an incognito window
|
|
const { newPage, newShareMenu, newContext } = await openNewTab(browser, {
|
|
url,
|
|
allowClipboard: true,
|
|
userProps: undefined,
|
|
})
|
|
|
|
// The second page should have the share button and not the error
|
|
await expect(newShareMenu.shareButton).toBeVisible()
|
|
await expect(newPage.getByTestId('tla-error')).not.toBeVisible()
|
|
|
|
// Now unshare it it...
|
|
await page.getByTestId('shared-link-shared-switch').click()
|
|
expect(await shareMenu.isToggleChecked()).toBe(false)
|
|
|
|
// Reload the second page
|
|
newPage.reload()
|
|
|
|
// The second page should have an error and not the share button
|
|
await expect(newShareMenu.shareButton).not.toBeVisible()
|
|
await expect(newPage.getByTestId('tla-error')).toBeVisible()
|
|
|
|
// Now reshare it...
|
|
await page.getByTestId('shared-link-shared-switch').click()
|
|
expect(await shareMenu.isToggleChecked()).toBe(true)
|
|
|
|
// Reload the second page again
|
|
newPage.reload()
|
|
|
|
// The second page should have the share button and not the error again
|
|
await expect(newShareMenu.shareButton).toBeVisible()
|
|
await expect(newPage.getByTestId('tla-error')).not.toBeVisible()
|
|
|
|
await newContext.close()
|
|
})
|
|
})
|
|
|
|
test.describe('signed in user on someone elses file', () => {
|
|
test('tabs work correctly', async ({ browser, sidebar, shareMenu }) => {
|
|
const newName = getRandomName()
|
|
await sidebar.renameFile(0, newName)
|
|
await shareMenu.open()
|
|
const url = await shareMenu.copyLink()
|
|
|
|
const parallelIndex = test.info().parallelIndex
|
|
// Open link in an incognito window
|
|
const { newShareMenu, newPage } = await openNewTab(browser, {
|
|
url,
|
|
allowClipboard: true,
|
|
userProps: { user: 'suppy', index: parallelIndex },
|
|
})
|
|
|
|
await expect(newPage.getByTestId('tla-sidebar').getByText(newName)).toBeVisible()
|
|
|
|
await newShareMenu.open()
|
|
expect(await newShareMenu.publishTabButton.isVisible()).toBe(false)
|
|
expect(await newShareMenu.inviteTabButton.isVisible()).toBe(false)
|
|
expect(await newShareMenu.exportTabButton.isVisible()).toBe(true)
|
|
expect(await newShareMenu.anonShareTabButton.isVisible()).toBe(true)
|
|
|
|
// Starts on the anon share tab
|
|
expect(await newShareMenu.inviteTabPage.isVisible()).toBe(false)
|
|
expect(await newShareMenu.exportTabPage.isVisible()).toBe(false)
|
|
expect(await newShareMenu.publishTabPage.isVisible()).toBe(false)
|
|
expect(await newShareMenu.anonShareTabPage.isVisible()).toBe(true)
|
|
|
|
// Can switch between tabs (export)
|
|
await newShareMenu.exportTabButton.click()
|
|
expect(await newShareMenu.inviteTabPage.isVisible()).toBe(false)
|
|
expect(await newShareMenu.exportTabPage.isVisible()).toBe(true)
|
|
expect(await newShareMenu.publishTabPage.isVisible()).toBe(false)
|
|
expect(await newShareMenu.anonShareTabPage.isVisible()).toBe(false)
|
|
})
|
|
})
|
|
|
|
test.describe('signed in user on published file', () => {
|
|
test('tabs work correctly', async ({ shareMenu, browser }) => {
|
|
// Publish the user's current file
|
|
await shareMenu.open()
|
|
expect(await shareMenu.isInviteButtonVisible()).toBe(true)
|
|
await shareMenu.publishFile()
|
|
const url = await shareMenu.copyLink()
|
|
|
|
// Open published file link in other user window
|
|
const { newShareMenu, newContext } = await openNewTab(browser, {
|
|
url,
|
|
allowClipboard: true,
|
|
userProps: { user: 'huppy', index: test.info().parallelIndex },
|
|
})
|
|
|
|
await expect(newShareMenu.shareButton).toBeVisible()
|
|
await newShareMenu.open()
|
|
|
|
expect(await newShareMenu.publishTabButton.isVisible()).toBe(false)
|
|
expect(await newShareMenu.inviteTabButton.isVisible()).toBe(false)
|
|
expect(await newShareMenu.exportTabButton.isVisible()).toBe(true)
|
|
expect(await newShareMenu.anonShareTabButton.isVisible()).toBe(true)
|
|
|
|
expect(await newShareMenu.publishTabPage.isVisible()).toBe(false)
|
|
expect(await newShareMenu.inviteTabPage.isVisible()).toBe(false)
|
|
expect(await newShareMenu.exportTabPage.isVisible()).toBe(false)
|
|
expect(await newShareMenu.anonShareTabPage.isVisible()).toBe(true) // show anon share tab page
|
|
|
|
// can copy the url
|
|
const copiedUrl = await newShareMenu.copyLink()
|
|
expect(new URL(copiedUrl).pathname).toBe(new URL(url).pathname)
|
|
|
|
// Switch to the export share tab
|
|
await newShareMenu.exportTabButton.click()
|
|
expect(await newShareMenu.exportTabPage.isVisible()).toBe(true)
|
|
expect(await newShareMenu.anonShareTabPage.isVisible()).toBe(false)
|
|
|
|
// Does not see the sidebar or the sidebar button
|
|
expect(await newShareMenu.page.getByTestId('tla-sidebar').count()).toBe(0)
|
|
expect(await newShareMenu.page.getByTestId('tla-sidebar-toggle').count()).toBe(0)
|
|
|
|
// Main user does see sidebar
|
|
expect(await shareMenu.page.getByTestId('tla-sidebar').count()).toBe(1)
|
|
expect(await shareMenu.page.getByTestId('tla-sidebar-toggle').count()).toBe(1)
|
|
|
|
await newContext.close()
|
|
})
|
|
})
|
|
|
|
test.describe('logged out user on scratch file', () => {
|
|
test('tabs work correctly', async ({ browser }) => {
|
|
const { newShareMenu, newContext } = await openNewTab(browser, {
|
|
allowClipboard: true,
|
|
userProps: undefined,
|
|
})
|
|
|
|
// In the incognito window, we are on the scratchpad
|
|
await expect(newShareMenu.shareButton).toBeVisible()
|
|
await newShareMenu.open()
|
|
expect(await newShareMenu.inviteTabButton.isVisible()).toBe(false)
|
|
expect(await newShareMenu.exportTabButton.isVisible()).toBe(true)
|
|
expect(await newShareMenu.publishTabButton.isVisible()).toBe(false)
|
|
expect(await newShareMenu.anonShareTabButton.isVisible()).toBe(false) // not shown on scratch
|
|
|
|
await newContext.close()
|
|
})
|
|
})
|
|
|
|
test.describe('logged out user on guest file', () => {
|
|
test('tabs work correctly', async ({ shareMenu, browser }) => {
|
|
// Share the signed in user's current file
|
|
await shareMenu.open()
|
|
expect(await shareMenu.isInviteButtonVisible()).toBe(true)
|
|
await shareMenu.shareFile()
|
|
const url = await shareMenu.copyLink()
|
|
|
|
// Open file link in an incognito window
|
|
const { newShareMenu, newContext } = await openNewTab(browser, {
|
|
url,
|
|
allowClipboard: true,
|
|
userProps: undefined,
|
|
})
|
|
|
|
await expect(newShareMenu.shareButton).toBeVisible()
|
|
await newShareMenu.open()
|
|
|
|
expect(await newShareMenu.publishTabButton.isVisible()).toBe(false)
|
|
expect(await newShareMenu.inviteTabButton.isVisible()).toBe(false)
|
|
expect(await newShareMenu.exportTabButton.isVisible()).toBe(true)
|
|
expect(await newShareMenu.anonShareTabButton.isVisible()).toBe(true)
|
|
|
|
expect(await newShareMenu.publishTabPage.isVisible()).toBe(false)
|
|
expect(await newShareMenu.inviteTabPage.isVisible()).toBe(false)
|
|
expect(await newShareMenu.exportTabPage.isVisible()).toBe(false)
|
|
expect(await newShareMenu.anonShareTabPage.isVisible()).toBe(true) // show anon share tab page
|
|
|
|
// can copy the url
|
|
const copiedUrl = await shareMenu.copyLink()
|
|
expect(copiedUrl).toBe(url)
|
|
|
|
// Switch to the export share tab
|
|
await newShareMenu.exportTabButton.click()
|
|
expect(await newShareMenu.exportTabPage.isVisible()).toBe(true)
|
|
expect(await newShareMenu.anonShareTabPage.isVisible()).toBe(false)
|
|
|
|
await newContext.close()
|
|
})
|
|
})
|
|
|
|
test.describe('logged out user on published file', () => {
|
|
test('tabs work correctly', async ({ shareMenu, browser }) => {
|
|
// Publish the user's current file
|
|
await shareMenu.open()
|
|
expect(await shareMenu.isInviteButtonVisible()).toBe(true)
|
|
await shareMenu.publishFile()
|
|
const url = await shareMenu.copyLink()
|
|
|
|
// Open published file link in an incognito window
|
|
const { newShareMenu, newContext, newEditor } = await openNewTab(browser, {
|
|
url,
|
|
allowClipboard: true,
|
|
userProps: undefined,
|
|
})
|
|
|
|
await expect(newShareMenu.shareButton).toBeVisible()
|
|
await newShareMenu.open()
|
|
|
|
expect(await newShareMenu.publishTabButton.isVisible()).toBe(false)
|
|
expect(await newShareMenu.inviteTabButton.isVisible()).toBe(false)
|
|
expect(await newShareMenu.exportTabButton.isVisible()).toBe(true)
|
|
expect(await newShareMenu.anonShareTabButton.isVisible()).toBe(true)
|
|
|
|
expect(await newShareMenu.publishTabPage.isVisible()).toBe(false)
|
|
expect(await newShareMenu.inviteTabPage.isVisible()).toBe(false)
|
|
expect(await newShareMenu.exportTabPage.isVisible()).toBe(false)
|
|
expect(await newShareMenu.anonShareTabPage.isVisible()).toBe(true) // show anon share tab page
|
|
|
|
// can copy the url
|
|
const copiedUrl = await shareMenu.copyLink()
|
|
expect(copiedUrl).toBe(url)
|
|
|
|
// Switch to the export share tab
|
|
await newShareMenu.exportTabButton.click()
|
|
expect(await newShareMenu.exportTabPage.isVisible()).toBe(true)
|
|
expect(await newShareMenu.anonShareTabPage.isVisible()).toBe(false)
|
|
|
|
// download the file
|
|
await newEditor.openPageMenu()
|
|
const downloadButton = newEditor.page.getByText('Download')
|
|
await expect(downloadButton).toBeVisible()
|
|
|
|
// check that the file downloaded
|
|
const downloadPromise = newEditor.page.waitForEvent('download')
|
|
|
|
await downloadButton.click()
|
|
const download = await downloadPromise
|
|
expect(download.suggestedFilename().endsWith('.tldr')).toBe(true)
|
|
|
|
await newContext.close()
|
|
})
|
|
})
|
|
|
|
/* ------------------- Exporting ------------------- */
|
|
test('can export a file as an image', async ({ page, shareMenu }) => {
|
|
await page.getByTestId('tools.rectangle').click()
|
|
await page.locator('.tl-background').click()
|
|
const downloadPromise = page.waitForEvent('download')
|
|
|
|
await shareMenu.open()
|
|
await shareMenu.exportFile()
|
|
const download = await downloadPromise
|
|
const suggestedFilename = download.suggestedFilename()
|
|
expect(suggestedFilename.endsWith('.png')).toBe(true)
|
|
const filePath = path.join('./test-results/', suggestedFilename)
|
|
await download.saveAs(filePath)
|
|
|
|
expect(fs.existsSync(filePath)).toBeTruthy()
|
|
const stats = fs.statSync(filePath)
|
|
expect(stats.size).toBeGreaterThan(0)
|
|
})
|
|
|
|
test('can follow a deep link to a never-seen file', async ({ editor, browser, shareMenu }) => {
|
|
const text = Math.random().toString(36).substring(2, 15)
|
|
await editor.createNewPage()
|
|
await editor.createTextShape(text)
|
|
|
|
await shareMenu.open()
|
|
expect(await shareMenu.isInviteButtonVisible()).toBe(true)
|
|
const url = await shareMenu.copyLink()
|
|
// close the share menu
|
|
await shareMenu.page.keyboard.press('Escape')
|
|
// create a new empty page
|
|
await editor.createNewPage()
|
|
|
|
const { newEditor } = await openNewTab(browser, {
|
|
url,
|
|
allowClipboard: true,
|
|
userProps: { user: 'suppy', index: test.info().parallelIndex },
|
|
})
|
|
|
|
await newEditor.expectShapesCount(1)
|
|
expect(newEditor.page.getByText(text).last()).toBeVisible()
|
|
})
|
|
|
|
test('can follow a deep link to an already-seen file', async ({ editor, shareMenu, browser }) => {
|
|
const text = Math.random().toString(36).substring(2, 15)
|
|
|
|
await shareMenu.open()
|
|
await shareMenu.inviteTabButton.click()
|
|
// close the share menu
|
|
await shareMenu.page.keyboard.press('Escape')
|
|
|
|
const { newEditor, newShareMenu } = await openNewTab(browser, {
|
|
url: editor.page.url(),
|
|
allowClipboard: true,
|
|
userProps: { user: 'suppy', index: test.info().parallelIndex },
|
|
})
|
|
|
|
await newEditor.createNewPage()
|
|
await newEditor.createTextShape(text)
|
|
await newEditor.expectShapesCount(1)
|
|
|
|
await newShareMenu.open()
|
|
await newShareMenu.anonShareTabButton.click()
|
|
const url = await newShareMenu.copyLink()
|
|
|
|
await newEditor.createNewPage()
|
|
|
|
await editor.page.goto(url)
|
|
await editor.expectShapesCount(1)
|
|
await expect(editor.page.getByText(text).last()).toBeVisible()
|
|
})
|